Merge "Made ManifestPath OptionalPath instead of Path"
diff --git a/Android.bp b/Android.bp
index 9d5b07d..8f7f3e2 100644
--- a/Android.bp
+++ b/Android.bp
@@ -47,101 +47,6 @@
//
toolchain_library {
- name: "libatomic",
- defaults: ["linux_bionic_supported"],
- vendor_available: true,
- product_available: true,
- ramdisk_available: true,
- vendor_ramdisk_available: true,
- recovery_available: true,
- native_bridge_supported: true,
-
- arch: {
- arm: {
- src: "prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/arm-linux-androideabi/lib/libatomic.a",
- },
- arm64: {
- src: "prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/aarch64-linux-android/lib64/libatomic.a",
- },
- x86: {
- src: "prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/x86_64-linux-android/lib/libatomic.a",
- },
- x86_64: {
- src: "prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/x86_64-linux-android/lib64/libatomic.a",
- },
- },
-}
-
-toolchain_library {
- name: "libgcc",
- defaults: ["linux_bionic_supported"],
- vendor_available: true,
- product_available: true,
- recovery_available: true,
- native_bridge_supported: true,
- apex_available: [
- "//apex_available:platform",
- "//apex_available:anyapex",
- ],
-
- arch: {
- arm: {
- src: "prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/lib/gcc/arm-linux-androideabi/4.9.x/libgcc.a",
- },
- arm64: {
- src: "prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/lib/gcc/aarch64-linux-android/4.9.x/libgcc.a",
- },
- x86: {
- src: "prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/lib/gcc/x86_64-linux-android/4.9.x/32/libgcc.a",
- },
- x86_64: {
- src: "prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/lib/gcc/x86_64-linux-android/4.9.x/libgcc.a",
- },
- },
-}
-
-toolchain_library {
- name: "libgcc_stripped",
- defaults: ["linux_bionic_supported"],
- vendor_available: true,
- product_available: true,
- ramdisk_available: true,
- vendor_ramdisk_available: true,
- recovery_available: true,
- native_bridge_supported: true,
- sdk_version: "current",
-
- arch: {
- arm: {
- src: "prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/lib/gcc/arm-linux-androideabi/4.9.x/libgcc.a",
- repack_objects_to_keep: [],
- enabled: false,
- },
- arm64: {
- src: "prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/lib/gcc/aarch64-linux-android/4.9.x/libgcc.a",
- repack_objects_to_keep: [
- "unwind-dw2.o",
- "unwind-dw2-fde-dip.o",
- ],
- },
- x86: {
- src: "prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/lib/gcc/x86_64-linux-android/4.9.x/32/libgcc.a",
- repack_objects_to_keep: [
- "unwind-dw2.o",
- "unwind-dw2-fde-dip.o",
- ],
- },
- x86_64: {
- src: "prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/lib/gcc/x86_64-linux-android/4.9.x/libgcc.a",
- repack_objects_to_keep: [
- "unwind-dw2.o",
- "unwind-dw2-fde-dip.o",
- ],
- },
- },
-}
-
-toolchain_library {
name: "libwinpthread",
host_supported: true,
enabled: false,
@@ -159,26 +64,6 @@
notice: ":mingw-libwinpthread-notice",
}
-toolchain_library {
- name: "libgcov",
- defaults: ["linux_bionic_supported"],
-
- arch: {
- arm: {
- src: "prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/lib/gcc/arm-linux-androideabi/4.9.x/libgcov.a",
- },
- arm64: {
- src: "prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/lib/gcc/aarch64-linux-android/4.9.x/libgcov.a",
- },
- x86: {
- src: "prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/lib/gcc/x86_64-linux-android/4.9.x/32/libgcov.a",
- },
- x86_64: {
- src: "prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/lib/gcc/x86_64-linux-android/4.9.x/libgcov.a",
- },
- },
-}
-
kernel_headers {
name: "device_kernel_headers",
vendor: true,
diff --git a/android/Android.bp b/android/Android.bp
index a32e8f2..f5e5606 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -78,9 +78,6 @@
"variable.go",
"visibility.go",
"writedocs.go",
-
- // Lock down environment access last
- "env.go",
],
testSrcs: [
"android_test.go",
diff --git a/android/androidmk.go b/android/androidmk.go
index 9317567..66a1036 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -546,7 +546,7 @@
}
if !amod.InRamdisk() && !amod.InVendorRamdisk() {
- a.AddStrings("LOCAL_INIT_RC", amod.commonProperties.Init_rc...)
+ a.AddPaths("LOCAL_FULL_INIT_RC", amod.initRcPaths)
}
a.AddStrings("LOCAL_VINTF_FRAGMENTS", amod.commonProperties.Vintf_fragments...)
a.SetBoolIfTrue("LOCAL_PROPRIETARY_MODULE", Bool(amod.commonProperties.Proprietary))
diff --git a/android/apex.go b/android/apex.go
index 7f9f0f5..25a07b8 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -43,10 +43,8 @@
// mergeApexVariations.
ApexVariationName string
- // Serialized ApiLevel that this module has to support at minimum. Should be accessed via
- // MinSdkVersion() method. Cannot be stored in its struct form because this is cloned into
- // properties structs, and ApiLevel has private members.
- MinSdkVersionStr string
+ // ApiLevel that this module has to support at minimum.
+ MinSdkVersion ApiLevel
// True if this module comes from an updatable apexBundle.
Updatable bool
@@ -82,19 +80,13 @@
// have to be built twice, but only once. In that case, the two apex variations apex.a and apex.b
// are configured to have the same alias variation named apex29.
func (i ApexInfo) mergedName(ctx PathContext) string {
- name := "apex" + strconv.Itoa(i.MinSdkVersion(ctx).FinalOrFutureInt())
+ name := "apex" + strconv.Itoa(i.MinSdkVersion.FinalOrFutureInt())
for _, sdk := range i.RequiredSdks {
name += "_" + sdk.Name + "_" + sdk.Version
}
return name
}
-// MinSdkVersion gives the api level that this module has to support at minimum. This is from the
-// min_sdk_version property of the containing apexBundle.
-func (i ApexInfo) MinSdkVersion(ctx PathContext) ApiLevel {
- return ApiLevelOrPanic(ctx, i.MinSdkVersionStr)
-}
-
// IsForPlatform tells whether this module is for the platform or not. If false is returned, it
// means that this apex variant of the module is built for an APEX.
func (i ApexInfo) IsForPlatform() bool {
@@ -919,7 +911,7 @@
"Consider adding 'min_sdk_version: %q' to %q",
minSdkVersion, ctx.ModuleName(), err.Error(),
ctx.GetPathString(false),
- minSdkVersion, ctx.ModuleName())
+ minSdkVersion, toName)
return false
}
}
diff --git a/android/apex_test.go b/android/apex_test.go
index b5323e8..109b1c8 100644
--- a/android/apex_test.go
+++ b/android/apex_test.go
@@ -33,10 +33,10 @@
{
name: "single",
in: []ApexInfo{
- {"foo", "current", false, nil, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, nil, []string{"foo"}, nil, NotForPrebuiltApex},
},
wantMerged: []ApexInfo{
- {"apex10000", "current", false, nil, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"apex10000", FutureApiLevel, false, nil, []string{"foo"}, nil, NotForPrebuiltApex},
},
wantAliases: [][2]string{
{"foo", "apex10000"},
@@ -45,11 +45,11 @@
{
name: "merge",
in: []ApexInfo{
- {"foo", "current", false, SdkRefs{{"baz", "1"}}, []string{"foo"}, nil, NotForPrebuiltApex},
- {"bar", "current", false, SdkRefs{{"baz", "1"}}, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"bar", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"bar"}, nil, NotForPrebuiltApex},
},
wantMerged: []ApexInfo{
- {"apex10000_baz_1", "current", false, SdkRefs{{"baz", "1"}}, []string{"bar", "foo"}, nil, false}},
+ {"apex10000_baz_1", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []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", "current", false, nil, []string{"foo"}, nil, NotForPrebuiltApex},
- {"bar", "30", false, nil, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, nil, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"bar", uncheckedFinalApiLevel(30), false, nil, []string{"bar"}, nil, NotForPrebuiltApex},
},
wantMerged: []ApexInfo{
- {"apex30", "30", false, nil, []string{"bar"}, nil, NotForPrebuiltApex},
- {"apex10000", "current", false, nil, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"apex30", uncheckedFinalApiLevel(30), false, nil, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"apex10000", FutureApiLevel, false, nil, []string{"foo"}, nil, NotForPrebuiltApex},
},
wantAliases: [][2]string{
{"bar", "apex30"},
@@ -73,11 +73,11 @@
{
name: "merge updatable",
in: []ApexInfo{
- {"foo", "current", false, nil, []string{"foo"}, nil, NotForPrebuiltApex},
- {"bar", "current", true, nil, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, nil, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"bar", FutureApiLevel, true, nil, []string{"bar"}, nil, NotForPrebuiltApex},
},
wantMerged: []ApexInfo{
- {"apex10000", "current", true, nil, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
+ {"apex10000", FutureApiLevel, true, nil, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
},
wantAliases: [][2]string{
{"bar", "apex10000"},
@@ -87,12 +87,12 @@
{
name: "don't merge sdks",
in: []ApexInfo{
- {"foo", "current", false, SdkRefs{{"baz", "1"}}, []string{"foo"}, nil, NotForPrebuiltApex},
- {"bar", "current", false, SdkRefs{{"baz", "2"}}, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"bar", FutureApiLevel, false, SdkRefs{{"baz", "2"}}, []string{"bar"}, nil, NotForPrebuiltApex},
},
wantMerged: []ApexInfo{
- {"apex10000_baz_2", "current", false, SdkRefs{{"baz", "2"}}, []string{"bar"}, nil, NotForPrebuiltApex},
- {"apex10000_baz_1", "current", false, SdkRefs{{"baz", "1"}}, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"apex10000_baz_2", FutureApiLevel, false, SdkRefs{{"baz", "2"}}, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"apex10000_baz_1", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []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", "current", false, nil, []string{"foo"}, nil, NotForPrebuiltApex},
- {"bar", "current", true, nil, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, nil, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"bar", FutureApiLevel, true, nil, []string{"bar"}, nil, NotForPrebuiltApex},
// This one should not be merged in with the others because it is for
// a prebuilt_apex.
- {"baz", "current", true, nil, []string{"baz"}, nil, ForPrebuiltApex},
+ {"baz", FutureApiLevel, true, nil, []string{"baz"}, nil, ForPrebuiltApex},
},
wantMerged: []ApexInfo{
- {"apex10000", "current", true, nil, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
- {"baz", "current", true, nil, []string{"baz"}, nil, ForPrebuiltApex},
+ {"apex10000", FutureApiLevel, true, nil, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
+ {"baz", FutureApiLevel, true, nil, []string{"baz"}, nil, ForPrebuiltApex},
},
wantAliases: [][2]string{
{"bar", "apex10000"},
diff --git a/android/arch.go b/android/arch.go
index 99bbe91..9f93752 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -166,7 +166,8 @@
return archType
}
-// ArchTypeList returns the 4 supported ArchTypes for arm, arm64, x86 and x86_64.
+// ArchTypeList returns the a slice copy of the 4 supported ArchTypes for arm,
+// arm64, x86 and x86_64.
func ArchTypeList() []ArchType {
return append([]ArchType(nil), archTypeList...)
}
@@ -265,7 +266,7 @@
DefaultDisabled: defDisabled,
}
- OsTypeList = append(OsTypeList, os)
+ osTypeList = append(osTypeList, os)
if _, found := commonTargetMap[name]; found {
panic(fmt.Errorf("Found Os type duplicate during OsType registration: %q", name))
@@ -279,7 +280,7 @@
// osByName returns the OsType that has the given name, or NoOsType if none match.
func osByName(name string) OsType {
- for _, os := range OsTypeList {
+ for _, os := range osTypeList {
if os.Name == name {
return os
}
@@ -311,9 +312,9 @@
}()
var (
- // OsTypeList contains a list of all the supported OsTypes, including ones not supported
+ // osTypeList contains a list of all the supported OsTypes, including ones not supported
// by the current build host or the target device.
- OsTypeList []OsType
+ osTypeList []OsType
// commonTargetMap maps names of OsTypes to the corresponding common Target, i.e. the
// Target with the same OsType and the common ArchType.
commonTargetMap = make(map[string]Target)
@@ -346,6 +347,11 @@
CommonArch = Arch{ArchType: Common}
)
+// OsTypeList returns a slice copy of the supported OsTypes.
+func OsTypeList() []OsType {
+ return append([]OsType(nil), osTypeList...)
+}
+
// Target specifies the OS and architecture that a module is being compiled for.
type Target struct {
// Os the OS that the module is being compiled for (e.g. "linux_glibc", "android").
@@ -447,7 +453,7 @@
// Collect a list of OSTypes supported by this module based on the HostOrDevice value
// passed to InitAndroidArchModule and the device_supported and host_supported properties.
var moduleOSList []OsType
- for _, os := range OsTypeList {
+ for _, os := range osTypeList {
for _, t := range mctx.Config().Targets[os] {
if base.supportsTarget(t) {
moduleOSList = append(moduleOSList, os)
@@ -611,7 +617,7 @@
}
// only the primary arch in the ramdisk / vendor_ramdisk / recovery partition
- if os == Android && (module.InstallInRecovery() || module.InstallInRamdisk() || module.InstallInVendorRamdisk()) {
+ if os == Android && (module.InstallInRecovery() || module.InstallInRamdisk() || module.InstallInVendorRamdisk() || module.InstallInDebugRamdisk()) {
osTargets = []Target{osTargets[0]}
}
@@ -837,7 +843,7 @@
"Arm_on_x86_64",
"Native_bridge",
}
- for _, os := range OsTypeList {
+ for _, os := range osTypeList {
// Add all the OSes.
targets = append(targets, os.Field)
@@ -1708,3 +1714,90 @@
}
return archToProp
}
+
+// 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.
+//
+// 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{}{}
+
+ // Nothing to do for non-OS/arch-specific modules.
+ if !m.ArchSpecific() {
+ return osToProp
+ }
+
+ // 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 {
+ 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
+ }
+ }
+ }
+ return osToProp
+}
diff --git a/android/bazel.go b/android/bazel.go
index 51ff3cb..9468891 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -108,6 +108,11 @@
type BazelConversionConfigEntry int
const (
+ // A sentinel value to be used as a key in Bp2BuildConfig for modules with
+ // no package path. This is also the module dir for top level Android.bp
+ // modules.
+ BP2BUILD_TOPLEVEL = "."
+
// iota + 1 ensures that the int value is not 0 when used in the Bp2buildAllowlist map,
// which can also mean that the key doesn't exist in a lookup.
@@ -124,54 +129,59 @@
// Configure modules in these directories to enable bp2build_available: true or false by default.
bp2buildDefaultConfig = Bp2BuildConfig{
"bionic": Bp2BuildDefaultTrueRecursively,
+ "external/gwp_asan": Bp2BuildDefaultTrueRecursively,
"system/core/libcutils": Bp2BuildDefaultTrueRecursively,
"system/logging/liblog": Bp2BuildDefaultTrueRecursively,
}
// Per-module denylist to always opt modules out.
bp2buildModuleDoNotConvertList = []string{
- "libBionicBenchmarksUtils", // ruperts@, cc_library_static
+ "libBionicBenchmarksUtils", // ruperts@, cc_library_static, 'map' file not found
"libbionic_spawn_benchmark", // ruperts@, cc_library_static, depends on //system/libbase
"libc_jemalloc_wrapper", // ruperts@, cc_library_static, depends on //external/jemalloc_new
- "libc_bootstrap", // ruperts@, cc_library_static
- "libc_init_static", // ruperts@, cc_library_static
- "libc_init_dynamic", // ruperts@, cc_library_static
- "libc_tzcode", // ruperts@, cc_library_static
- "libc_freebsd", // ruperts@, cc_library_static
- "libc_freebsd_large_stack", // ruperts@, cc_library_static
- "libc_netbsd", // ruperts@, cc_library_static
- "libc_openbsd_ndk", // ruperts@, cc_library_static
- "libc_openbsd_large_stack", // ruperts@, cc_library_static
- "libc_openbsd", // ruperts@, cc_library_static
- "libc_gdtoa", // ruperts@, cc_library_static
- "libc_fortify", // ruperts@, cc_library_static
- "libc_bionic", // ruperts@, cc_library_static
+ "libc_bootstrap", // ruperts@, cc_library_static, 'private/bionic_auxv.h' file not found
+ "libc_init_static", // ruperts@, cc_library_static, 'private/bionic_elf_tls.h' file not found
+ "libc_init_dynamic", // ruperts@, cc_library_static, 'private/bionic_defs.h' file not found
+ "libc_tzcode", // ruperts@, cc_library_static, error: expected expression
+ "libc_netbsd", // ruperts@, cc_library_static, 'engine.c' file not found
+ "libc_openbsd_large_stack", // ruperts@, cc_library_static, 'android/log.h' file not found
+ "libc_openbsd", // ruperts@, cc_library_static, 'android/log.h' file not found
+ "libc_fortify", // ruperts@, cc_library_static, 'private/bionic_fortify.h' file not found
+ "libc_bionic", // ruperts@, cc_library_static, 'private/bionic_asm.h' file not found
"libc_bionic_ndk", // ruperts@, cc_library_static, depends on //bionic/libc/system_properties
- "libc_bionic_systrace", // ruperts@, cc_library_static
- "libc_pthread", // ruperts@, cc_library_static
- "libc_syscalls", // ruperts@, cc_library_static
- "libc_aeabi", // ruperts@, cc_library_static
+ "libc_bionic_systrace", // ruperts@, cc_library_static, 'private/bionic_systrace.h' file not found
+ "libc_pthread", // ruperts@, cc_library_static, 'private/bionic_defs.h' file not found
+ "libc_syscalls", // ruperts@, cc_library_static, mutator panic cannot get direct dep syscalls-arm64.S of libc_syscalls
"libc_ndk", // ruperts@, cc_library_static, depends on //bionic/libm:libm
"libc_nopthread", // ruperts@, cc_library_static, depends on //external/arm-optimized-routines
"libc_common", // ruperts@, cc_library_static, depends on //bionic/libc:libc_nopthread
- "libc_static_dispatch", // ruperts@, cc_library_static
- "libc_dynamic_dispatch", // ruperts@, cc_library_static
"libc_common_static", // ruperts@, cc_library_static, depends on //bionic/libc:libc_common
"libc_common_shared", // ruperts@, cc_library_static, depends on //bionic/libc:libc_common
- "libc_unwind_static", // ruperts@, cc_library_static
+ "libc_unwind_static", // ruperts@, cc_library_static, 'private/bionic_elf_tls.h' file not found
"libc_nomalloc", // ruperts@, cc_library_static, depends on //bionic/libc:libc_common
- "libasync_safe", // ruperts@, cc_library_static
+ "libasync_safe", // ruperts@, cc_library_static, 'private/CachedProperty.h' file not found
"libc_malloc_debug_backtrace", // ruperts@, cc_library_static, depends on //system/libbase
"libsystemproperties", // ruperts@, cc_library_static, depends on //system/core/property_service/libpropertyinfoparser
- "libdl_static", // ruperts@, cc_library_static
+ "libdl_static", // ruperts@, cc_library_static, 'private/CFIShadow.h' file not found
"liblinker_main", // ruperts@, cc_library_static, depends on //system/libbase
"liblinker_malloc", // ruperts@, cc_library_static, depends on //system/logging/liblog:liblog
"liblinker_debuggerd_stub", // ruperts@, cc_library_static, depends on //system/libbase
- "libbionic_tests_headers_posix", // ruperts@, cc_library_static
- "libc_dns", // ruperts@, cc_library_static
- "generated_android_ids", // cparsons@, genrule
- "note_memtag_heap_async", // cparsons@, cc_library_static
- "note_memtag_heap_sync", // cparsons@, cc_library_static
+ "libbionic_tests_headers_posix", // ruperts@, cc_library_static, 'complex.h' file not found
+ "libc_dns", // ruperts@, cc_library_static, 'android/log.h' file not found
+
+ // List of all full_cc_libraries in //bionic, with their immediate failures
+ "libc", // jingwen@, cc_library, depends on //external/gwp_asan
+ "libc_malloc_debug", // jingwen@, cc_library, fatal error: 'assert.h' file not found
+ "libc_malloc_hooks", // jingwen@, cc_library, fatal error: 'errno.h' file not found
+ "libdl", // jingwen@, cc_library, ld.lld: error: no input files
+ "libm", // jingwen@, cc_library, fatal error: 'freebsd-compat.h' file not found
+ "libseccomp_policy", // jingwen@, cc_library, fatal error: 'seccomp_policy.h' file not found
+ "libstdc++", // jingwen@, cc_library, depends on //external/gwp_asan
+
+ // For mixed builds specifically
+ "note_memtag_heap_async", // jingwen@, cc_library_static, OK for bp2build but features.h includes not found for mixed builds (b/185079815)
+ "note_memtag_heap_sync", // jingwen@, cc_library_static, OK for bp2build but features.h includes not found for mixed builds (b/185079815)
+ "libc_gdtoa", // ruperts@, cc_library_static, OK for bp2build but undefined symbol: __strtorQ for mixed builds
}
// Used for quicker lookups
@@ -224,10 +234,15 @@
func bp2buildDefaultTrueRecursively(packagePath string, config Bp2BuildConfig) bool {
ret := false
+ // Return exact matches in the config.
+ if config[packagePath] == Bp2BuildDefaultTrueRecursively {
+ return true
+ }
if config[packagePath] == Bp2BuildDefaultFalse {
return false
}
+ // If not, check for the config recursively.
packagePrefix := ""
// e.g. for x/y/z, iterate over x, x/y, then x/y/z, taking the final value from the allowlist.
for _, part := range strings.Split(packagePath, "/") {
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index ba5231f..8d561d2 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -34,17 +34,26 @@
"android/soong/shared"
)
-type CqueryRequestType int
+type cqueryRequest interface {
+ // Name returns a string name for this request type. Such request type names must be unique,
+ // and must only consist of alphanumeric characters.
+ Name() string
-const (
- getAllFiles CqueryRequestType = iota
- getAllFilesAndCcObjectFiles
-)
+ // StarlarkFunctionBody returns a starlark function body to process this request type.
+ // The returned string is the body of a Starlark function which obtains
+ // all request-relevant information about a target and returns a string containing
+ // this information.
+ // The function should have the following properties:
+ // - `target` is the only parameter to this function (a configured target).
+ // - The return value must be a string.
+ // - The function body should not be indented outside of its own scope.
+ StarlarkFunctionBody() string
+}
// Map key to describe bazel cquery requests.
type cqueryKey struct {
label string
- requestType cquery.RequestType
+ requestType cqueryRequest
archType ArchType
}
@@ -58,7 +67,7 @@
// TODO(cparsons): Other cquery-related methods should be added here.
// Returns the results of GetOutputFiles and GetCcObjectFiles in a single query (in that order).
- GetOutputFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool)
+ GetCcInfo(label string, archType ArchType) (cquery.CcInfo, bool, error)
// ** End cquery methods
@@ -76,16 +85,24 @@
BuildStatementsToRegister() []bazel.BuildStatement
}
-// A context object which tracks queued requests that need to be made to Bazel,
-// and their results after the requests have been made.
-type bazelContext struct {
+type bazelRunner interface {
+ issueBazelCommand(paths *bazelPaths, runName bazel.RunName, command bazelCommand, extraFlags ...string) (string, string, error)
+}
+
+type bazelPaths struct {
homeDir string
bazelPath string
outputBase string
workspaceDir string
buildDir string
metricsDir string
+}
+// A context object which tracks queued requests that need to be made to Bazel,
+// and their results after the requests have been made.
+type bazelContext struct {
+ bazelRunner
+ paths *bazelPaths
requests map[cqueryKey]bool // cquery requests that have not yet been issued to Bazel
requestMutex sync.Mutex // requests can be written in parallel
@@ -104,17 +121,20 @@
// A bazel context to use for tests.
type MockBazelContext struct {
- AllFiles map[string][]string
+ OutputBaseDir string
+
+ LabelToOutputFiles map[string][]string
+ LabelToCcInfo map[string]cquery.CcInfo
}
func (m MockBazelContext) GetOutputFiles(label string, archType ArchType) ([]string, bool) {
- result, ok := m.AllFiles[label]
+ result, ok := m.LabelToOutputFiles[label]
return result, ok
}
-func (m MockBazelContext) GetOutputFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) {
- result, ok := m.AllFiles[label]
- return result, result, ok
+func (m MockBazelContext) GetCcInfo(label string, archType ArchType) (cquery.CcInfo, bool, error) {
+ result, ok := m.LabelToCcInfo[label]
+ return result, ok, nil
}
func (m MockBazelContext) InvokeBazel() error {
@@ -125,9 +145,7 @@
return true
}
-func (m MockBazelContext) OutputBase() string {
- return "outputbase"
-}
+func (m MockBazelContext) OutputBase() string { return m.OutputBaseDir }
func (m MockBazelContext) BuildStatementsToRegister() []bazel.BuildStatement {
return []bazel.BuildStatement{}
@@ -140,31 +158,31 @@
var ret []string
if ok {
bazelOutput := strings.TrimSpace(rawString)
- ret = cquery.GetOutputFiles.ParseResult(bazelOutput).([]string)
+ ret = cquery.GetOutputFiles.ParseResult(bazelOutput)
}
return ret, ok
}
-func (bazelCtx *bazelContext) GetOutputFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) {
- var outputFiles []string
- var ccObjects []string
-
- result, ok := bazelCtx.cquery(label, cquery.GetOutputFilesAndCcObjectFiles, archType)
- if ok {
- bazelOutput := strings.TrimSpace(result)
- returnResult := cquery.GetOutputFilesAndCcObjectFiles.ParseResult(bazelOutput).(cquery.GetOutputFilesAndCcObjectFiles_Result)
- outputFiles = returnResult.OutputFiles
- ccObjects = returnResult.CcObjectFiles
+func (bazelCtx *bazelContext) GetCcInfo(label string, archType ArchType) (cquery.CcInfo, bool, error) {
+ result, ok := bazelCtx.cquery(label, cquery.GetCcInfo, archType)
+ if !ok {
+ return cquery.CcInfo{}, ok, nil
}
- return outputFiles, ccObjects, ok
+ bazelOutput := strings.TrimSpace(result)
+ ret, err := cquery.GetCcInfo.ParseResult(bazelOutput)
+ return ret, ok, err
}
func (n noopBazelContext) GetOutputFiles(label string, archType ArchType) ([]string, bool) {
panic("unimplemented")
}
-func (n noopBazelContext) GetOutputFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) {
+func (n noopBazelContext) GetCcInfo(label string, archType ArchType) (cquery.CcInfo, bool, error) {
+ panic("unimplemented")
+}
+
+func (n noopBazelContext) GetPrebuiltCcStaticLibraryFiles(label string, archType ArchType) ([]string, bool) {
panic("unimplemented")
}
@@ -191,42 +209,56 @@
return noopBazelContext{}, nil
}
- bazelCtx := bazelContext{buildDir: c.buildDir, requests: make(map[cqueryKey]bool)}
+ p, err := bazelPathsFromConfig(c)
+ if err != nil {
+ return nil, err
+ }
+ return &bazelContext{
+ bazelRunner: &builtinBazelRunner{},
+ paths: p,
+ requests: make(map[cqueryKey]bool),
+ }, nil
+}
+
+func bazelPathsFromConfig(c *config) (*bazelPaths, error) {
+ p := bazelPaths{
+ buildDir: c.buildDir,
+ }
missingEnvVars := []string{}
if len(c.Getenv("BAZEL_HOME")) > 1 {
- bazelCtx.homeDir = c.Getenv("BAZEL_HOME")
+ p.homeDir = c.Getenv("BAZEL_HOME")
} else {
missingEnvVars = append(missingEnvVars, "BAZEL_HOME")
}
if len(c.Getenv("BAZEL_PATH")) > 1 {
- bazelCtx.bazelPath = c.Getenv("BAZEL_PATH")
+ p.bazelPath = c.Getenv("BAZEL_PATH")
} else {
missingEnvVars = append(missingEnvVars, "BAZEL_PATH")
}
if len(c.Getenv("BAZEL_OUTPUT_BASE")) > 1 {
- bazelCtx.outputBase = c.Getenv("BAZEL_OUTPUT_BASE")
+ p.outputBase = c.Getenv("BAZEL_OUTPUT_BASE")
} else {
missingEnvVars = append(missingEnvVars, "BAZEL_OUTPUT_BASE")
}
if len(c.Getenv("BAZEL_WORKSPACE")) > 1 {
- bazelCtx.workspaceDir = c.Getenv("BAZEL_WORKSPACE")
+ p.workspaceDir = c.Getenv("BAZEL_WORKSPACE")
} else {
missingEnvVars = append(missingEnvVars, "BAZEL_WORKSPACE")
}
if len(c.Getenv("BAZEL_METRICS_DIR")) > 1 {
- bazelCtx.metricsDir = c.Getenv("BAZEL_METRICS_DIR")
+ p.metricsDir = c.Getenv("BAZEL_METRICS_DIR")
} else {
missingEnvVars = append(missingEnvVars, "BAZEL_METRICS_DIR")
}
if len(missingEnvVars) > 0 {
return nil, errors.New(fmt.Sprintf("missing required env vars to use bazel: %s", missingEnvVars))
} else {
- return &bazelCtx, nil
+ return &p, nil
}
}
-func (context *bazelContext) BazelMetricsDir() string {
- return context.metricsDir
+func (p *bazelPaths) BazelMetricsDir() string {
+ return p.metricsDir
}
func (context *bazelContext) BazelEnabled() bool {
@@ -238,7 +270,7 @@
// If the given request was already made (and the results are available), then
// returns (result, true). If the request is queued but no results are available,
// then returns ("", false).
-func (context *bazelContext) cquery(label string, requestType cquery.RequestType,
+func (context *bazelContext) cquery(label string, requestType cqueryRequest,
archType ArchType) (string, bool) {
key := cqueryKey{label, requestType, archType}
if result, ok := context.results[key]; ok {
@@ -259,31 +291,64 @@
return ""
}
+type bazelCommand struct {
+ command string
+ // query or label
+ expression string
+}
+
+type mockBazelRunner struct {
+ bazelCommandResults map[bazelCommand]string
+ commands []bazelCommand
+}
+
+func (r *mockBazelRunner) issueBazelCommand(paths *bazelPaths,
+ runName bazel.RunName,
+ command bazelCommand,
+ extraFlags ...string) (string, string, error) {
+ r.commands = append(r.commands, command)
+ if ret, ok := r.bazelCommandResults[command]; ok {
+ return ret, "", nil
+ }
+ return "", "", nil
+}
+
+type builtinBazelRunner struct{}
+
// Issues the given bazel command with given build label and additional flags.
// Returns (stdout, stderr, error). The first and second return values are strings
// containing the stdout and stderr of the run command, and an error is returned if
// the invocation returned an error code.
-func (context *bazelContext) issueBazelCommand(runName bazel.RunName, command string, labels []string,
+func (r *builtinBazelRunner) issueBazelCommand(paths *bazelPaths, runName bazel.RunName, command bazelCommand,
extraFlags ...string) (string, string, error) {
+ cmdFlags := []string{"--output_base=" + paths.outputBase, command.command}
+ cmdFlags = append(cmdFlags, command.expression)
+ cmdFlags = append(cmdFlags, "--package_path=%workspace%/"+paths.intermediatesDir())
+ cmdFlags = append(cmdFlags, "--profile="+shared.BazelMetricsFilename(paths, runName))
- cmdFlags := []string{"--output_base=" + context.outputBase, command}
- cmdFlags = append(cmdFlags, labels...)
- cmdFlags = append(cmdFlags, "--package_path=%workspace%/"+context.intermediatesDir())
- cmdFlags = append(cmdFlags, "--profile="+shared.BazelMetricsFilename(context, runName))
- // Set default platforms to canonicalized values for mixed builds requests. If these are set
- // in the bazelrc, they will have values that are non-canonicalized, and thus be invalid.
- // The actual platform values here may be overridden by configuration transitions from the buildroot.
+ // Set default platforms to canonicalized values for mixed builds requests.
+ // If these are set in the bazelrc, they will have values that are
+ // non-canonicalized to @sourceroot labels, and thus be invalid when
+ // referenced from the buildroot.
+ //
+ // The actual platform values here may be overridden by configuration
+ // transitions from the buildroot.
cmdFlags = append(cmdFlags,
- fmt.Sprintf("--platforms=%s", canonicalizeLabel("//build/bazel/platforms:generic_x86_64")))
+ fmt.Sprintf("--platforms=%s", canonicalizeLabel("//build/bazel/platforms:android_x86_64")))
cmdFlags = append(cmdFlags,
fmt.Sprintf("--extra_toolchains=%s", canonicalizeLabel("//prebuilts/clang/host/linux-x86:all")))
+ // This should be parameterized on the host OS, but let's restrict to linux
+ // to keep things simple for now.
+ cmdFlags = append(cmdFlags,
+ fmt.Sprintf("--host_platform=%s", canonicalizeLabel("//build/bazel/platforms:linux_x86_64")))
+
// Explicitly disable downloading rules (such as canonical C++ and Java rules) from the network.
cmdFlags = append(cmdFlags, "--experimental_repository_disable_download")
cmdFlags = append(cmdFlags, extraFlags...)
- bazelCmd := exec.Command(context.bazelPath, cmdFlags...)
- bazelCmd.Dir = context.workspaceDir
- bazelCmd.Env = append(os.Environ(), "HOME="+context.homeDir, pwdPrefix(),
+ bazelCmd := exec.Command(paths.bazelPath, cmdFlags...)
+ bazelCmd.Dir = paths.workspaceDir
+ bazelCmd.Env = append(os.Environ(), "HOME="+paths.homeDir, pwdPrefix(),
// Disables local host detection of gcc; toolchain information is defined
// explicitly in BUILD files.
"BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1")
@@ -307,15 +372,20 @@
# This file is generated by soong_build. Do not edit.
local_repository(
name = "sourceroot",
- path = "%s",
+ path = "%[1]s",
)
local_repository(
name = "rules_cc",
- path = "%s/build/bazel/rules_cc",
+ path = "%[1]s/build/bazel/rules_cc",
+)
+
+local_repository(
+ name = "bazel_skylib",
+ path = "%[1]s/build/bazel/bazel_skylib",
)
`
- return []byte(fmt.Sprintf(formatString, context.workspaceDir, context.workspaceDir))
+ return []byte(fmt.Sprintf(formatString, context.paths.workspaceDir))
}
func (context *bazelContext) mainBzlFileContents() []byte {
@@ -328,7 +398,7 @@
def _config_node_transition_impl(settings, attr):
return {
- "//command_line_option:platforms": "@sourceroot//build/bazel/platforms:generic_%s" % attr.arch,
+ "//command_line_option:platforms": "@sourceroot//build/bazel/platforms:android_%s" % attr.arch,
}
_config_node_transition = transition(
@@ -446,7 +516,7 @@
// and grouped by their request type. The data retrieved for each label depends on its
// request type.
func (context *bazelContext) cqueryStarlarkFileContents() []byte {
- requestTypeToCqueryIdEntries := map[cquery.RequestType][]string{}
+ requestTypeToCqueryIdEntries := map[cqueryRequest][]string{}
for val, _ := range context.requests {
cqueryId := getCqueryId(val)
mapEntryString := fmt.Sprintf("%q : True", cqueryId)
@@ -471,7 +541,7 @@
return id_string + ">>" + %s(target)
`
- for _, requestType := range cquery.RequestTypes {
+ for requestType, _ := range requestTypeToCqueryIdEntries {
labelMapName := requestType.Name() + "_Labels"
functionName := requestType.Name() + "_Fn"
labelRegistrationMapSection += fmt.Sprintf(mapDeclarationFormatString,
@@ -504,10 +574,10 @@
platform_name = build_options(target)["//command_line_option:platforms"][0].name
if platform_name == "host":
return "HOST"
- elif not platform_name.startswith("generic_"):
- fail("expected platform name of the form 'generic_<arch>', but was " + str(platforms))
+ elif not platform_name.startswith("android_"):
+ fail("expected platform name of the form 'android_<arch>', but was " + str(platforms))
return "UNKNOWN"
- return platform_name[len("generic_"):]
+ return platform_name[len("android_"):]
def format(target):
id_string = str(target.label) + "|" + get_arch(target)
@@ -525,8 +595,8 @@
// Returns a workspace-relative path containing build-related metadata required
// for interfacing with Bazel. Example: out/soong/bazel.
-func (context *bazelContext) intermediatesDir() string {
- return filepath.Join(context.buildDir, "bazel")
+func (p *bazelPaths) intermediatesDir() string {
+ return filepath.Join(p.buildDir, "bazel")
}
// Issues commands to Bazel to receive results for all cquery requests
@@ -538,7 +608,7 @@
var cqueryErr string
var err error
- intermediatesDirPath := absolutePath(context.intermediatesDir())
+ intermediatesDirPath := absolutePath(context.paths.intermediatesDir())
if _, err := os.Stat(intermediatesDirPath); os.IsNotExist(err) {
err = os.Mkdir(intermediatesDirPath, 0777)
}
@@ -547,38 +617,38 @@
return err
}
err = ioutil.WriteFile(
- absolutePath(filepath.Join(context.intermediatesDir(), "main.bzl")),
+ filepath.Join(intermediatesDirPath, "main.bzl"),
context.mainBzlFileContents(), 0666)
if err != nil {
return err
}
err = ioutil.WriteFile(
- absolutePath(filepath.Join(context.intermediatesDir(), "BUILD.bazel")),
+ filepath.Join(intermediatesDirPath, "BUILD.bazel"),
context.mainBuildFileContents(), 0666)
if err != nil {
return err
}
- cqueryFileRelpath := filepath.Join(context.intermediatesDir(), "buildroot.cquery")
+ cqueryFileRelpath := filepath.Join(context.paths.intermediatesDir(), "buildroot.cquery")
err = ioutil.WriteFile(
absolutePath(cqueryFileRelpath),
context.cqueryStarlarkFileContents(), 0666)
if err != nil {
return err
}
- workspaceFileRelpath := filepath.Join(context.intermediatesDir(), "WORKSPACE.bazel")
err = ioutil.WriteFile(
- absolutePath(workspaceFileRelpath),
+ filepath.Join(intermediatesDirPath, "WORKSPACE.bazel"),
context.workspaceFileContents(), 0666)
if err != nil {
return err
}
buildrootLabel := "//:buildroot"
- cqueryOutput, cqueryErr, err = context.issueBazelCommand(bazel.CqueryBuildRootRunName, "cquery",
- []string{fmt.Sprintf("kind(rule, deps(%s))", buildrootLabel)},
+ cqueryOutput, cqueryErr, err = context.issueBazelCommand(
+ context.paths,
+ bazel.CqueryBuildRootRunName,
+ bazelCommand{"cquery", fmt.Sprintf("kind(rule, deps(%s))", buildrootLabel)},
"--output=starlark",
"--starlark:file="+cqueryFileRelpath)
- err = ioutil.WriteFile(
- absolutePath(filepath.Join(context.intermediatesDir(), "cquery.out")),
+ err = ioutil.WriteFile(filepath.Join(intermediatesDirPath, "cquery.out"),
[]byte(cqueryOutput), 0666)
if err != nil {
return err
@@ -609,11 +679,13 @@
//
// TODO(cparsons): Use --target_pattern_file to avoid command line limits.
var aqueryOutput string
- aqueryOutput, _, err = context.issueBazelCommand(bazel.AqueryBuildRootRunName, "aquery",
- []string{fmt.Sprintf("deps(%s)", buildrootLabel),
- // Use jsonproto instead of proto; actual proto parsing would require a dependency on Bazel's
- // proto sources, which would add a number of unnecessary dependencies.
- "--output=jsonproto"})
+ aqueryOutput, _, err = context.issueBazelCommand(
+ context.paths,
+ bazel.AqueryBuildRootRunName,
+ bazelCommand{"aquery", fmt.Sprintf("deps(%s)", buildrootLabel)},
+ // Use jsonproto instead of proto; actual proto parsing would require a dependency on Bazel's
+ // proto sources, which would add a number of unnecessary dependencies.
+ "--output=jsonproto")
if err != nil {
return err
@@ -627,8 +699,10 @@
// Issue a build command of the phony root to generate symlink forests for dependencies of the
// Bazel build. This is necessary because aquery invocations do not generate this symlink forest,
// but some of symlinks may be required to resolve source dependencies of the build.
- _, _, err = context.issueBazelCommand(bazel.BazelBuildPhonyRootRunName, "build",
- []string{"//:phonyroot"})
+ _, _, err = context.issueBazelCommand(
+ context.paths,
+ bazel.BazelBuildPhonyRootRunName,
+ bazelCommand{"build", "//:phonyroot"})
if err != nil {
return err
@@ -644,7 +718,7 @@
}
func (context *bazelContext) OutputBase() string {
- return context.outputBase
+ return context.paths.outputBase
}
// Singleton used for registering BUILD file ninja dependencies (needed
@@ -663,7 +737,7 @@
// Add ninja file dependencies for files which all bazel invocations require.
bazelBuildList := absolutePath(filepath.Join(
- filepath.Dir(bootstrap.CmdlineModuleListFile()), "bazel.list"))
+ filepath.Dir(bootstrap.CmdlineArgs.ModuleListFile), "bazel.list"))
ctx.AddNinjaFileDeps(bazelBuildList)
data, err := ioutil.ReadFile(bazelBuildList)
@@ -678,7 +752,7 @@
// Register bazel-owned build statements (obtained from the aquery invocation).
for index, buildStatement := range ctx.Config().BazelContext.BuildStatementsToRegister() {
if len(buildStatement.Command) < 1 {
- panic(fmt.Sprintf("unhandled build statement: %s", buildStatement))
+ panic(fmt.Sprintf("unhandled build statement: %v", buildStatement))
}
rule := NewRuleBuilder(pctx, ctx)
cmd := rule.Command()
diff --git a/android/bazel_handler_test.go b/android/bazel_handler_test.go
new file mode 100644
index 0000000..85f701f
--- /dev/null
+++ b/android/bazel_handler_test.go
@@ -0,0 +1,118 @@
+package android
+
+import (
+ "os"
+ "path/filepath"
+ "reflect"
+ "testing"
+)
+
+func TestRequestResultsAfterInvokeBazel(t *testing.T) {
+ label := "//foo:bar"
+ arch := Arm64
+ bazelContext, _ := testBazelContext(t, map[bazelCommand]string{
+ bazelCommand{command: "cquery", expression: "kind(rule, deps(//:buildroot))"}: `@sourceroot//foo:bar|arm64>>out/foo/bar.txt`,
+ })
+ g, ok := bazelContext.GetOutputFiles(label, arch)
+ if ok {
+ t.Errorf("Did not expect cquery results prior to running InvokeBazel(), but got %s", g)
+ }
+ err := bazelContext.InvokeBazel()
+ if err != nil {
+ t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
+ }
+ g, ok = bazelContext.GetOutputFiles(label, arch)
+ if !ok {
+ t.Errorf("Expected cquery results after running InvokeBazel(), but got none")
+ } else if w := []string{"out/foo/bar.txt"}; !reflect.DeepEqual(w, g) {
+ t.Errorf("Expected output %s, got %s", w, g)
+ }
+}
+
+func TestInvokeBazelWritesBazelFiles(t *testing.T) {
+ bazelContext, baseDir := testBazelContext(t, map[bazelCommand]string{})
+ err := bazelContext.InvokeBazel()
+ if err != nil {
+ t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
+ }
+ if _, err := os.Stat(filepath.Join(baseDir, "bazel", "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, "bazel", "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)
+ }
+
+ if _, err := os.Stat(filepath.Join(baseDir, "bazel", "WORKSPACE.bazel")); os.IsNotExist(err) {
+ t.Errorf("Expected WORKSPACE.bazel to exist, but it does not")
+ } else if err != nil {
+ t.Errorf("Unexpected error stating WORKSPACE.bazel %s", err)
+ }
+}
+
+func TestInvokeBazelPopulatesBuildStatements(t *testing.T) {
+ bazelContext, _ := testBazelContext(t, map[bazelCommand]string{
+ bazelCommand{command: "aquery", expression: "deps(//:buildroot)"}: `
+{
+ "artifacts": [{
+ "id": 1,
+ "pathFragmentId": 1
+ }, {
+ "id": 2,
+ "pathFragmentId": 2
+ }],
+ "actions": [{
+ "targetId": 1,
+ "actionKey": "x",
+ "mnemonic": "x",
+ "arguments": ["touch", "foo"],
+ "inputDepSetIds": [1],
+ "outputIds": [1],
+ "primaryOutputId": 1
+ }],
+ "depSetOfFiles": [{
+ "id": 1,
+ "directArtifactIds": [1, 2]
+ }],
+ "pathFragments": [{
+ "id": 1,
+ "label": "one"
+ }, {
+ "id": 2,
+ "label": "two"
+ }]
+}`,
+ })
+ err := bazelContext.InvokeBazel()
+ if err != nil {
+ t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
+ }
+
+ got := bazelContext.BuildStatementsToRegister()
+ if want := 1; len(got) != want {
+ t.Errorf("Expected %d registered build statements, got %#v", want, got)
+ }
+}
+
+func testBazelContext(t *testing.T, bazelCommandResults map[bazelCommand]string) (*bazelContext, string) {
+ t.Helper()
+ p := bazelPaths{
+ buildDir: t.TempDir(),
+ outputBase: "outputbase",
+ workspaceDir: "workspace_dir",
+ }
+ aqueryCommand := bazelCommand{command: "aquery", expression: "deps(//:buildroot)"}
+ if _, exists := bazelCommandResults[aqueryCommand]; !exists {
+ bazelCommandResults[aqueryCommand] = "{}\n"
+ }
+ runner := &mockBazelRunner{bazelCommandResults: bazelCommandResults}
+ return &bazelContext{
+ bazelRunner: runner,
+ paths: &p,
+ requests: map[cqueryKey]bool{},
+ }, p.buildDir
+}
diff --git a/android/config.go b/android/config.go
index cfbc37f..3db7980 100644
--- a/android/config.go
+++ b/android/config.go
@@ -345,7 +345,7 @@
// multiple runs in the same program execution is carried over (such as Bazel
// context or environment deps).
func ConfigForAdditionalRun(c Config) (Config, error) {
- newConfig, err := NewConfig(c.srcDir, c.buildDir, c.moduleListFile)
+ newConfig, err := NewConfig(c.srcDir, c.buildDir, c.moduleListFile, c.env)
if err != nil {
return Config{}, err
}
@@ -356,12 +356,12 @@
// NewConfig creates a new Config object. The srcDir argument specifies the path
// to the root source directory. It also loads the config file, if found.
-func NewConfig(srcDir, buildDir string, moduleListFile string) (Config, error) {
+func NewConfig(srcDir, buildDir string, moduleListFile string, availableEnv map[string]string) (Config, error) {
// Make a config with default options.
config := &config{
ProductVariablesFileName: filepath.Join(buildDir, productVariablesFileName),
- env: originalEnv,
+ env: availableEnv,
srcDir: srcDir,
buildDir: buildDir,
@@ -1259,7 +1259,7 @@
if len(c.productVariables.CFIIncludePaths) == 0 {
return false
}
- return HasAnyPrefix(path, c.productVariables.CFIIncludePaths)
+ return HasAnyPrefix(path, c.productVariables.CFIIncludePaths) && !c.CFIDisabledForPath(path)
}
func (c *config) MemtagHeapDisabledForPath(path string) bool {
@@ -1273,14 +1273,14 @@
if len(c.productVariables.MemtagHeapAsyncIncludePaths) == 0 {
return false
}
- return HasAnyPrefix(path, c.productVariables.MemtagHeapAsyncIncludePaths)
+ return HasAnyPrefix(path, c.productVariables.MemtagHeapAsyncIncludePaths) && !c.MemtagHeapDisabledForPath(path)
}
func (c *config) MemtagHeapSyncEnabledForPath(path string) bool {
if len(c.productVariables.MemtagHeapSyncIncludePaths) == 0 {
return false
}
- return HasAnyPrefix(path, c.productVariables.MemtagHeapSyncIncludePaths)
+ return HasAnyPrefix(path, c.productVariables.MemtagHeapSyncIncludePaths) && !c.MemtagHeapDisabledForPath(path)
}
func (c *config) VendorConfig(name string) VendorConfig {
@@ -1295,10 +1295,6 @@
return Bool(c.productVariables.Aml_abis)
}
-func (c *config) ExcludeDraftNdkApis() bool {
- return Bool(c.productVariables.Exclude_draft_ndk_apis)
-}
-
func (c *config) FlattenApex() bool {
return Bool(c.productVariables.Flatten_apex)
}
@@ -1498,6 +1494,10 @@
return c.config.productVariables.BuildBrokenTrebleSyspropNeverallow
}
+func (c *deviceConfig) BuildDebugfsRestrictionsEnabled() bool {
+ return c.config.productVariables.BuildDebugfsRestrictionsEnabled
+}
+
func (c *deviceConfig) BuildBrokenVendorPropertyNamespace() bool {
return c.config.productVariables.BuildBrokenVendorPropertyNamespace
}
diff --git a/android/env.go b/android/env.go
deleted file mode 100644
index 725a145..0000000
--- a/android/env.go
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2015 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 (
- "android/soong/shared"
-)
-
-// This file supports dependencies on environment variables. During build
-// manifest generation, any dependency on an environment variable is added to a
-// list. At the end of the build, a JSON file called soong.environment.used is
-// written containing the current value of all used environment variables. The
-// next time the top-level build script is run, soong_ui parses the compare the
-// contents of the used environment variables, then, if they changed, deletes
-// soong.environment.used to cause a rebuild.
-//
-// The dependency of build.ninja on soong.environment.used is declared in
-// build.ninja.d
-
-var originalEnv map[string]string
-
-func InitEnvironment(envFile string) {
- var err error
- originalEnv, err = shared.EnvFromFile(envFile)
- if err != nil {
- panic(err)
- }
-}
diff --git a/android/image.go b/android/image.go
index 1a1a423..bdb9be0 100644
--- a/android/image.go
+++ b/android/image.go
@@ -30,6 +30,11 @@
// vendor ramdisk partition).
VendorRamdiskVariantNeeded(ctx BaseModuleContext) bool
+ // DebugRamdiskVariantNeeded should return true if the module needs a debug ramdisk variant (installed on the
+ // debug ramdisk partition: $(PRODUCT_OUT)/debug_ramdisk/first_stage_ramdisk if BOARD_USES_RECOVERY_AS_ROOT is
+ // true, $(PRODUCT_OUT)/debug_ramdisk otherise).
+ DebugRamdiskVariantNeeded(ctx BaseModuleContext) bool
+
// RecoveryVariantNeeded should return true if the module needs a recovery variant (installed on the
// recovery partition).
RecoveryVariantNeeded(ctx BaseModuleContext) bool
@@ -60,6 +65,9 @@
// VendorRamdiskVariation means a module to be installed to vendor ramdisk image.
VendorRamdiskVariation string = "vendor_ramdisk"
+
+ // DebugRamdiskVariation means a module to be installed to debug ramdisk image.
+ DebugRamdiskVariation string = "debug_ramdisk"
)
// imageMutator creates variants for modules that implement the ImageInterface that
@@ -83,6 +91,9 @@
if m.VendorRamdiskVariantNeeded(ctx) {
variations = append(variations, VendorRamdiskVariation)
}
+ if m.DebugRamdiskVariantNeeded(ctx) {
+ variations = append(variations, DebugRamdiskVariation)
+ }
if m.RecoveryVariantNeeded(ctx) {
variations = append(variations, RecoveryVariation)
}
diff --git a/android/module.go b/android/module.go
index 9f923e2..942e071 100644
--- a/android/module.go
+++ b/android/module.go
@@ -393,6 +393,7 @@
InstallInSanitizerDir() bool
InstallInRamdisk() bool
InstallInVendorRamdisk() bool
+ InstallInDebugRamdisk() bool
InstallInRecovery() bool
InstallInRoot() bool
InstallBypassMake() bool
@@ -450,6 +451,7 @@
InstallInSanitizerDir() bool
InstallInRamdisk() bool
InstallInVendorRamdisk() bool
+ InstallInDebugRamdisk() bool
InstallInRecovery() bool
InstallInRoot() bool
InstallBypassMake() bool
@@ -753,6 +755,9 @@
// Whether this module is installed to vendor ramdisk
Vendor_ramdisk *bool
+ // Whether this module is installed to debug ramdisk
+ Debug_ramdisk *bool
+
// Whether this module is built for non-native architectures (also known as native bridge binary)
Native_bridge_supported *bool `android:"arch_variant"`
@@ -1540,6 +1545,10 @@
return Bool(m.commonProperties.Vendor_ramdisk)
}
+func (m *ModuleBase) InstallInDebugRamdisk() bool {
+ return Bool(m.commonProperties.Debug_ramdisk)
+}
+
func (m *ModuleBase) InstallInRecovery() bool {
return Bool(m.commonProperties.Recovery)
}
@@ -1593,6 +1602,10 @@
return m.base().commonProperties.ImageVariation == VendorRamdiskVariation
}
+func (m *ModuleBase) InDebugRamdisk() bool {
+ return m.base().commonProperties.ImageVariation == DebugRamdiskVariation
+}
+
func (m *ModuleBase) InRecovery() bool {
return m.base().commonProperties.ImageVariation == RecoveryVariation
}
@@ -2548,6 +2561,10 @@
return m.module.InstallInVendorRamdisk()
}
+func (m *moduleContext) InstallInDebugRamdisk() bool {
+ return m.module.InstallInDebugRamdisk()
+}
+
func (m *moduleContext) InstallInRecovery() bool {
return m.module.InstallInRecovery()
}
diff --git a/android/paths.go b/android/paths.go
index ba1ab11..c303c38 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -107,6 +107,7 @@
InstallInSanitizerDir() bool
InstallInRamdisk() bool
InstallInVendorRamdisk() bool
+ InstallInDebugRamdisk() bool
InstallInRecovery() bool
InstallInRoot() bool
InstallBypassMake() bool
@@ -416,11 +417,101 @@
return labels
}
+// Returns true if a prefix + components[:i] + /Android.bp exists
+// TODO(b/185358476) Could check for BUILD file instead of checking for Android.bp file, or ensure BUILD is always generated?
+func directoryHasBlueprint(fs pathtools.FileSystem, prefix string, components []string, componentIndex int) bool {
+ blueprintPath := prefix
+ if blueprintPath != "" {
+ blueprintPath = blueprintPath + "/"
+ }
+ blueprintPath = blueprintPath + strings.Join(components[:componentIndex+1], "/")
+ blueprintPath = blueprintPath + "/Android.bp"
+ if exists, _, _ := fs.Exists(blueprintPath); exists {
+ return true
+ } else {
+ return false
+ }
+}
+
+// Transform a path (if necessary) to acknowledge package boundaries
+//
+// e.g. something like
+// async_safe/include/async_safe/CHECK.h
+// might become
+// //bionic/libc/async_safe:include/async_safe/CHECK.h
+// if the "async_safe" directory is actually a package and not just a directory.
+//
+// In particular, paths that extend into packages are transformed into absolute labels beginning with //.
+func transformSubpackagePath(ctx BazelConversionPathContext, path bazel.Label) bazel.Label {
+ var newPath bazel.Label
+
+ // Don't transform Bp_text
+ newPath.Bp_text = path.Bp_text
+
+ if strings.HasPrefix(path.Label, "//") {
+ // Assume absolute labels are already correct (e.g. //path/to/some/package:foo.h)
+ newPath.Label = path.Label
+ return newPath
+ }
+
+ newLabel := ""
+ pathComponents := strings.Split(path.Label, "/")
+ foundBlueprint := false
+ // Check the deepest subdirectory first and work upwards
+ for i := len(pathComponents) - 1; i >= 0; i-- {
+ pathComponent := pathComponents[i]
+ var sep string
+ if !foundBlueprint && directoryHasBlueprint(ctx.Config().fs, ctx.ModuleDir(), pathComponents, i) {
+ sep = ":"
+ foundBlueprint = true
+ } else {
+ sep = "/"
+ }
+ if newLabel == "" {
+ newLabel = pathComponent
+ } else {
+ newLabel = pathComponent + sep + newLabel
+ }
+ }
+ if foundBlueprint {
+ // Ensure paths end up looking like //bionic/... instead of //./bionic/...
+ moduleDir := ctx.ModuleDir()
+ if strings.HasPrefix(moduleDir, ".") {
+ moduleDir = moduleDir[1:]
+ }
+ // Make the path into an absolute label (e.g. //bionic/libc/foo:bar.h instead of just foo:bar.h)
+ if moduleDir == "" {
+ newLabel = "//" + newLabel
+ } else {
+ newLabel = "//" + moduleDir + "/" + newLabel
+ }
+ }
+ newPath.Label = newLabel
+
+ return newPath
+}
+
+// Transform paths to acknowledge package boundaries
+// See transformSubpackagePath() for more information
+func transformSubpackagePaths(ctx BazelConversionPathContext, paths bazel.LabelList) bazel.LabelList {
+ var newPaths bazel.LabelList
+ for _, include := range paths.Includes {
+ newPaths.Includes = append(newPaths.Includes, transformSubpackagePath(ctx, include))
+ }
+ for _, exclude := range paths.Excludes {
+ newPaths.Excludes = append(newPaths.Excludes, transformSubpackagePath(ctx, exclude))
+ }
+ return newPaths
+}
+
// BazelLabelForModuleSrc returns bazel.LabelList with paths rooted from the module's local source
// directory. It expands globs, and resolves references to modules using the ":name" syntax to
// bazel-compatible labels. Properties passed as the paths or excludes argument must have been
// annotated with struct tag `android:"path"` so that dependencies on other modules will have
// already been handled by the path_properties mutator.
+//
+// With expanded globs, we can catch package boundaries problem instead of
+// silently failing to potentially missing files from Bazel's globs.
func BazelLabelForModuleSrc(ctx BazelConversionPathContext, paths []string) bazel.LabelList {
return BazelLabelForModuleSrcExcludes(ctx, paths, []string(nil))
}
@@ -431,6 +522,9 @@
// passed as the paths or excludes argument must have been annotated with struct tag
// `android:"path"` so that dependencies on other modules will have already been handled by the
// path_properties mutator.
+//
+// With expanded globs, we can catch package boundaries problem instead of
+// silently failing to potentially missing files from Bazel's globs.
func BazelLabelForModuleSrcExcludes(ctx BazelConversionPathContext, paths, excludes []string) bazel.LabelList {
excludeLabels := expandSrcsForBazel(ctx, excludes, []string(nil))
excluded := make([]string, 0, len(excludeLabels.Includes))
@@ -439,6 +533,7 @@
}
labels := expandSrcsForBazel(ctx, paths, excluded)
labels.Excludes = excludeLabels.Includes
+ labels = transformSubpackagePaths(ctx, labels)
return labels
}
@@ -1095,11 +1190,12 @@
// a single file.
files, err = gctx.GlobWithDeps(path.String(), nil)
} else {
- var deps []string
+ var result pathtools.GlobResult
// We cannot add build statements in this context, so we fall back to
// AddNinjaFileDeps
- files, deps, err = ctx.Config().fs.Glob(path.String(), nil, pathtools.FollowSymlinks)
- ctx.AddNinjaFileDeps(deps...)
+ result, err = ctx.Config().fs.Glob(path.String(), nil, pathtools.FollowSymlinks)
+ ctx.AddNinjaFileDeps(result.Deps...)
+ files = result.Matches
}
if err != nil {
@@ -1842,6 +1938,16 @@
if !ctx.InstallInRoot() {
partition += "/system"
}
+ } else if ctx.InstallInDebugRamdisk() {
+ // The module is only available after switching root into
+ // /first_stage_ramdisk. To expose the module before switching root
+ // on a device without a dedicated recovery partition, install the
+ // recovery variant.
+ if ctx.DeviceConfig().BoardUsesRecoveryAsBoot() {
+ partition = "debug_ramdisk/first_stage_ramdisk"
+ } else {
+ partition = "debug_ramdisk"
+ }
} else if ctx.InstallInRecovery() {
if ctx.InstallInRoot() {
partition = "recovery/root"
@@ -2012,6 +2118,7 @@
inSanitizerDir bool
inRamdisk bool
inVendorRamdisk bool
+ inDebugRamdisk bool
inRecovery bool
inRoot bool
forceOS *OsType
@@ -2044,6 +2151,10 @@
return m.inVendorRamdisk
}
+func (m testModuleInstallPathContext) InstallInDebugRamdisk() bool {
+ return m.inDebugRamdisk
+}
+
func (m testModuleInstallPathContext) InstallInRecovery() bool {
return m.inRecovery
}
diff --git a/android/paths_test.go b/android/paths_test.go
index 465ea3b..cb9138b 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -21,6 +21,8 @@
"strconv"
"strings"
"testing"
+
+ "github.com/google/blueprint/proptools"
)
type strsTestCase struct {
@@ -339,6 +341,73 @@
},
{
+ name: "ramdisk binary",
+ ctx: &testModuleInstallPathContext{
+ baseModuleContext: baseModuleContext{
+ os: deviceTarget.Os,
+ target: deviceTarget,
+ },
+ inRamdisk: true,
+ },
+ in: []string{"my_test"},
+ out: "target/product/test_device/ramdisk/system/my_test",
+ partitionDir: "target/product/test_device/ramdisk/system",
+ },
+ {
+ name: "ramdisk root binary",
+ ctx: &testModuleInstallPathContext{
+ baseModuleContext: baseModuleContext{
+ os: deviceTarget.Os,
+ target: deviceTarget,
+ },
+ inRamdisk: true,
+ inRoot: true,
+ },
+ in: []string{"my_test"},
+ out: "target/product/test_device/ramdisk/my_test",
+ partitionDir: "target/product/test_device/ramdisk",
+ },
+ {
+ name: "vendor_ramdisk binary",
+ ctx: &testModuleInstallPathContext{
+ baseModuleContext: baseModuleContext{
+ os: deviceTarget.Os,
+ target: deviceTarget,
+ },
+ inVendorRamdisk: true,
+ },
+ in: []string{"my_test"},
+ out: "target/product/test_device/vendor_ramdisk/system/my_test",
+ partitionDir: "target/product/test_device/vendor_ramdisk/system",
+ },
+ {
+ name: "vendor_ramdisk root binary",
+ ctx: &testModuleInstallPathContext{
+ baseModuleContext: baseModuleContext{
+ os: deviceTarget.Os,
+ target: deviceTarget,
+ },
+ inVendorRamdisk: true,
+ inRoot: true,
+ },
+ in: []string{"my_test"},
+ out: "target/product/test_device/vendor_ramdisk/my_test",
+ partitionDir: "target/product/test_device/vendor_ramdisk",
+ },
+ {
+ name: "debug_ramdisk binary",
+ ctx: &testModuleInstallPathContext{
+ baseModuleContext: baseModuleContext{
+ os: deviceTarget.Os,
+ target: deviceTarget,
+ },
+ inDebugRamdisk: true,
+ },
+ in: []string{"my_test"},
+ out: "target/product/test_device/debug_ramdisk/my_test",
+ partitionDir: "target/product/test_device/debug_ramdisk",
+ },
+ {
name: "system native test binary",
ctx: &testModuleInstallPathContext{
baseModuleContext: baseModuleContext{
@@ -635,6 +704,80 @@
}
}
+func TestPathForModuleInstallRecoveryAsBoot(t *testing.T) {
+ testConfig := pathTestConfig("")
+ testConfig.TestProductVariables.BoardUsesRecoveryAsBoot = proptools.BoolPtr(true)
+ testConfig.TestProductVariables.BoardMoveRecoveryResourcesToVendorBoot = proptools.BoolPtr(true)
+ deviceTarget := Target{Os: Android, Arch: Arch{ArchType: Arm64}}
+
+ testCases := []struct {
+ name string
+ ctx *testModuleInstallPathContext
+ in []string
+ out string
+ partitionDir string
+ }{
+ {
+ name: "ramdisk binary",
+ ctx: &testModuleInstallPathContext{
+ baseModuleContext: baseModuleContext{
+ os: deviceTarget.Os,
+ target: deviceTarget,
+ },
+ inRamdisk: true,
+ inRoot: true,
+ },
+ in: []string{"my_test"},
+ out: "target/product/test_device/recovery/root/first_stage_ramdisk/my_test",
+ partitionDir: "target/product/test_device/recovery/root/first_stage_ramdisk",
+ },
+
+ {
+ name: "vendor_ramdisk binary",
+ ctx: &testModuleInstallPathContext{
+ baseModuleContext: baseModuleContext{
+ os: deviceTarget.Os,
+ target: deviceTarget,
+ },
+ inVendorRamdisk: true,
+ inRoot: true,
+ },
+ in: []string{"my_test"},
+ out: "target/product/test_device/vendor_ramdisk/first_stage_ramdisk/my_test",
+ partitionDir: "target/product/test_device/vendor_ramdisk/first_stage_ramdisk",
+ },
+ {
+ name: "debug_ramdisk binary",
+ ctx: &testModuleInstallPathContext{
+ baseModuleContext: baseModuleContext{
+ os: deviceTarget.Os,
+ target: deviceTarget,
+ },
+ inDebugRamdisk: true,
+ },
+ in: []string{"my_test"},
+ out: "target/product/test_device/debug_ramdisk/first_stage_ramdisk/my_test",
+ partitionDir: "target/product/test_device/debug_ramdisk/first_stage_ramdisk",
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ tc.ctx.baseModuleContext.config = testConfig
+ output := PathForModuleInstall(tc.ctx, tc.in...)
+ if output.basePath.path != tc.out {
+ t.Errorf("unexpected path:\n got: %q\nwant: %q\n",
+ output.basePath.path,
+ tc.out)
+ }
+ if output.partitionDir != tc.partitionDir {
+ t.Errorf("unexpected partitionDir:\n got: %q\nwant: %q\n",
+ output.partitionDir, tc.partitionDir)
+ }
+ })
+ }
+}
+
func TestBaseDirForInstallPath(t *testing.T) {
testConfig := pathTestConfig("")
deviceTarget := Target{Os: Android, Arch: Arch{ArchType: Arm64}}
diff --git a/android/prebuilt.go b/android/prebuilt.go
index ebccaa7..40bcdfd 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -82,6 +82,12 @@
}
func (p *Prebuilt) Name(name string) string {
+ return PrebuiltNameFromSource(name)
+}
+
+// PrebuiltNameFromSource returns the result of prepending the "prebuilt_" prefix to the supplied
+// name.
+func PrebuiltNameFromSource(name string) string {
return "prebuilt_" + name
}
@@ -93,22 +99,24 @@
return proptools.Bool(p.properties.Prefer)
}
-// The below source-related functions and the srcs, src fields are based on an assumption that
-// prebuilt modules have a static source property at the moment. Currently there is only one
-// exception, android_app_import, which chooses a source file depending on the product's DPI
-// preference configs. We'll want to add native support for dynamic source cases if we end up having
-// more modules like this.
-func (p *Prebuilt) SingleSourcePath(ctx ModuleContext) Path {
- if p.srcsSupplier != nil {
- srcs := p.srcsSupplier(ctx, ctx.Module())
+// SingleSourcePathFromSupplier invokes the supplied supplier for the current module in the
+// supplied context to retrieve a list of file paths, ensures that the returned list of file paths
+// contains a single value and then assumes that is a module relative file path and converts it to
+// a Path accordingly.
+//
+// Any issues, such as nil supplier or not exactly one file path will be reported as errors on the
+// supplied context and this will return nil.
+func SingleSourcePathFromSupplier(ctx ModuleContext, srcsSupplier PrebuiltSrcsSupplier, srcsPropertyName string) Path {
+ if srcsSupplier != nil {
+ srcs := srcsSupplier(ctx, ctx.Module())
if len(srcs) == 0 {
- ctx.PropertyErrorf(p.srcsPropertyName, "missing prebuilt source file")
+ ctx.PropertyErrorf(srcsPropertyName, "missing prebuilt source file")
return nil
}
if len(srcs) > 1 {
- ctx.PropertyErrorf(p.srcsPropertyName, "multiple prebuilt source files")
+ ctx.PropertyErrorf(srcsPropertyName, "multiple prebuilt source files")
return nil
}
@@ -122,6 +130,15 @@
}
}
+// The below source-related functions and the srcs, src fields are based on an assumption that
+// prebuilt modules have a static source property at the moment. Currently there is only one
+// exception, android_app_import, which chooses a source file depending on the product's DPI
+// preference configs. We'll want to add native support for dynamic source cases if we end up having
+// more modules like this.
+func (p *Prebuilt) SingleSourcePath(ctx ModuleContext) Path {
+ return SingleSourcePathFromSupplier(ctx, p.srcsSupplier, p.srcsPropertyName)
+}
+
func (p *Prebuilt) UsePrebuilt() bool {
return p.properties.UsePrebuilt
}
@@ -213,6 +230,26 @@
Prebuilt() *Prebuilt
}
+// IsModulePreferred returns true if the given module is preferred.
+//
+// A source module is preferred if there is no corresponding prebuilt module or the prebuilt module
+// does not have "prefer: true".
+//
+// A prebuilt module is preferred if there is no corresponding source module or the prebuilt module
+// has "prefer: true".
+func IsModulePreferred(module Module) bool {
+ if module.IsReplacedByPrebuilt() {
+ // A source module that has been replaced by a prebuilt counterpart.
+ return false
+ }
+ if prebuilt, ok := module.(PrebuiltInterface); ok {
+ if p := prebuilt.Prebuilt(); p != nil {
+ return p.UsePrebuilt()
+ }
+ }
+ return true
+}
+
func RegisterPrebuiltsPreArchMutators(ctx RegisterMutatorsContext) {
ctx.BottomUp("prebuilt_rename", PrebuiltRenameMutator).Parallel()
}
@@ -302,6 +339,13 @@
return false
}
+ // Skip prebuilt modules under unexported namespaces so that we won't
+ // end up shadowing non-prebuilt module when prebuilt module under same
+ // name happens to have a `Prefer` property set to true.
+ if ctx.Config().KatiEnabled() && !prebuilt.ExportedToMake() {
+ return false
+ }
+
// TODO: use p.Properties.Name and ctx.ModuleDir to override preference
if Bool(p.properties.Prefer) {
return true
diff --git a/android/sdk_version.go b/android/sdk_version.go
index ce22b5f..98db824 100644
--- a/android/sdk_version.go
+++ b/android/sdk_version.go
@@ -22,15 +22,15 @@
type SdkContext interface {
// SdkVersion returns SdkSpec that corresponds to the sdk_version property of the current module
- SdkVersion() SdkSpec
+ SdkVersion(ctx EarlyModuleContext) SdkSpec
// SystemModules returns the system_modules property of the current module, or an empty string if it is not set.
SystemModules() string
// MinSdkVersion returns SdkSpec that corresponds to the min_sdk_version property of the current module,
// or from sdk_version if it is not set.
- MinSdkVersion() SdkSpec
+ MinSdkVersion(ctx EarlyModuleContext) SdkSpec
// TargetSdkVersion returns the SdkSpec that corresponds to the target_sdk_version property of the current module,
// or from sdk_version if it is not set.
- TargetSdkVersion() SdkSpec
+ TargetSdkVersion(ctx EarlyModuleContext) SdkSpec
}
// SdkKind represents a particular category of an SDK spec like public, system, test, etc.
@@ -75,58 +75,15 @@
}
}
-// SdkVersion represents a specific version number of an SDK spec of a particular kind
-type SdkVersion int
-
-const (
- // special version number for a not-yet-frozen SDK
- SdkVersionCurrent SdkVersion = SdkVersion(FutureApiLevelInt)
- // special version number to be used for SDK specs where version number doesn't
- // make sense, e.g. "none", "", etc.
- SdkVersionNone SdkVersion = SdkVersion(0)
-)
-
-// IsCurrent checks if the SdkVersion refers to the not-yet-published version of an SdkKind
-func (v SdkVersion) IsCurrent() bool {
- return v == SdkVersionCurrent
-}
-
-// IsNumbered checks if the SdkVersion refers to the published (a.k.a numbered) version of an SdkKind
-func (v SdkVersion) IsNumbered() bool {
- return !v.IsCurrent() && v != SdkVersionNone
-}
-
-// String returns the string representation of this SdkVersion.
-func (v SdkVersion) String() string {
- if v.IsCurrent() {
- return "current"
- } else if v.IsNumbered() {
- return strconv.Itoa(int(v))
- }
- return "(no version)"
-}
-
-func (v SdkVersion) ApiLevel(ctx EarlyModuleContext) ApiLevel {
- return ApiLevelOrPanic(ctx, v.String())
-}
-
-// AsNumberString directly converts the numeric value of this sdk version as a string.
-// When isNumbered() is true, this method is the same as String(). However, for SdkVersionCurrent
-// and SdkVersionNone, this returns 10000 and 0 while String() returns "current" and "(no version"),
-// respectively.
-func (v SdkVersion) AsNumberString() string {
- return strconv.Itoa(int(v))
-}
-
// SdkSpec represents the kind and the version of an SDK for a module to build against
type SdkSpec struct {
- Kind SdkKind
- Version SdkVersion
- Raw string
+ Kind SdkKind
+ ApiLevel ApiLevel
+ Raw string
}
func (s SdkSpec) String() string {
- return fmt.Sprintf("%s_%s", s.Kind, s.Version)
+ return fmt.Sprintf("%s_%s", s.Kind, s.ApiLevel)
}
// Valid checks if this SdkSpec is well-formed. Note however that true doesn't mean that the
@@ -177,10 +134,10 @@
}
if s.Kind == SdkPublic || s.Kind == SdkSystem {
- if s.Version.IsCurrent() {
+ if s.ApiLevel.IsCurrent() {
if i, err := strconv.Atoi(currentSdkVersion); err == nil {
- version := SdkVersion(i)
- return SdkSpec{s.Kind, version, s.Raw}
+ apiLevel := uncheckedFinalApiLevel(i)
+ return SdkSpec{s.Kind, apiLevel, s.Raw}
}
panic(fmt.Errorf("BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES must be either \"current\" or a number, but was %q", currentSdkVersion))
}
@@ -190,10 +147,10 @@
// UsePrebuilt determines whether prebuilt SDK should be used for this SdkSpec with the given context.
func (s SdkSpec) UsePrebuilt(ctx EarlyModuleContext) bool {
- if s.Version.IsCurrent() {
+ if s.ApiLevel.IsCurrent() {
// "current" can be built from source and be from prebuilt SDK
return ctx.Config().AlwaysUsePrebuiltSdks()
- } else if s.Version.IsNumbered() {
+ } else if !s.ApiLevel.IsPreview() {
// validation check
if s.Kind != SdkPublic && s.Kind != SdkSystem && s.Kind != SdkTest && s.Kind != SdkModule {
panic(fmt.Errorf("prebuilt SDK is not not available for SdkKind=%q", s.Kind))
@@ -206,50 +163,68 @@
return false
}
-// EffectiveVersion converts an SdkSpec into the concrete SdkVersion that the module
-// should use. For modules targeting an unreleased SDK (meaning it does not yet have a number)
-// it returns FutureApiLevel(10000).
-func (s SdkSpec) EffectiveVersion(ctx EarlyModuleContext) (SdkVersion, error) {
+// EffectiveVersion converts an SdkSpec into the concrete ApiLevel that the module should use. For
+// modules targeting an unreleased SDK (meaning it does not yet have a number) it returns
+// FutureApiLevel(10000).
+func (s SdkSpec) EffectiveVersion(ctx EarlyModuleContext) (ApiLevel, error) {
if !s.Valid() {
- return s.Version, fmt.Errorf("invalid sdk version %q", s.Raw)
+ return s.ApiLevel, fmt.Errorf("invalid sdk version %q", s.Raw)
}
if ctx.DeviceSpecific() || ctx.SocSpecific() {
s = s.ForVendorPartition(ctx)
}
- if s.Version.IsNumbered() {
- return s.Version, nil
+ if !s.ApiLevel.IsPreview() {
+ return s.ApiLevel, nil
}
- return SdkVersion(ctx.Config().DefaultAppTargetSdk(ctx).FinalOrFutureInt()), nil
+ ret := ctx.Config().DefaultAppTargetSdk(ctx)
+ if ret.IsPreview() {
+ return FutureApiLevel, nil
+ }
+ return ret, nil
}
// EffectiveVersionString converts an SdkSpec into the concrete version string that the module
// should use. For modules targeting an unreleased SDK (meaning it does not yet have a number)
// it returns the codename (P, Q, R, etc.)
func (s SdkSpec) EffectiveVersionString(ctx EarlyModuleContext) (string, error) {
- ver, err := s.EffectiveVersion(ctx)
- if err == nil && int(ver) == ctx.Config().DefaultAppTargetSdk(ctx).FinalOrFutureInt() {
- return ctx.Config().DefaultAppTargetSdk(ctx).String(), nil
+ if !s.Valid() {
+ return s.ApiLevel.String(), fmt.Errorf("invalid sdk version %q", s.Raw)
}
- return ver.String(), err
+
+ if ctx.DeviceSpecific() || ctx.SocSpecific() {
+ s = s.ForVendorPartition(ctx)
+ }
+ if !s.ApiLevel.IsPreview() {
+ return s.ApiLevel.String(), nil
+ }
+ return ctx.Config().DefaultAppTargetSdk(ctx).String(), nil
}
-func SdkSpecFrom(str string) SdkSpec {
+var (
+ SdkSpecNone = SdkSpec{SdkNone, NoneApiLevel, "(no version)"}
+ // TODO(b/175678607) ApiLevel of SdkSpecPrivate should be FutureApiLevel
+ SdkSpecPrivate = SdkSpec{SdkPrivate, NoneApiLevel, ""}
+ // TODO(b/175678607) ApiLevel of SdkSpecCorePlatform should be FutureApiLevel
+ SdkSpecCorePlatform = SdkSpec{SdkCorePlatform, NoneApiLevel, "core_platform"}
+)
+
+func SdkSpecFrom(ctx EarlyModuleContext, str string) SdkSpec {
switch str {
// special cases first
case "":
- return SdkSpec{SdkPrivate, SdkVersionNone, str}
+ return SdkSpecPrivate
case "none":
- return SdkSpec{SdkNone, SdkVersionNone, str}
+ return SdkSpecNone
case "core_platform":
- return SdkSpec{SdkCorePlatform, SdkVersionNone, str}
+ return SdkSpecCorePlatform
default:
// the syntax is [kind_]version
sep := strings.LastIndex(str, "_")
var kindString string
if sep == 0 {
- return SdkSpec{SdkInvalid, SdkVersionNone, str}
+ return SdkSpec{SdkInvalid, NoneApiLevel, str}
} else if sep == -1 {
kindString = ""
} else {
@@ -272,19 +247,14 @@
case "system_server":
kind = SdkSystemServer
default:
- return SdkSpec{SdkInvalid, SdkVersionNone, str}
+ return SdkSpec{SdkInvalid, NoneApiLevel, str}
}
- var version SdkVersion
- if versionString == "current" {
- version = SdkVersionCurrent
- } else if i, err := strconv.Atoi(versionString); err == nil {
- version = SdkVersion(i)
- } else {
- return SdkSpec{SdkInvalid, SdkVersionNone, str}
+ apiLevel, err := ApiLevelFromUser(ctx, versionString)
+ if err != nil {
+ return SdkSpec{SdkInvalid, apiLevel, str}
}
-
- return SdkSpec{kind, version, str}
+ return SdkSpec{kind, apiLevel, str}
}
}
@@ -292,7 +262,7 @@
// Ensures that the specified system SDK version is one of BOARD_SYSTEMSDK_VERSIONS (for vendor/product Java module)
// Assuming that BOARD_SYSTEMSDK_VERSIONS := 28 29,
// sdk_version of the modules in vendor/product that use system sdk must be either system_28, system_29 or system_current
- if s.Kind != SdkSystem || !s.Version.IsNumbered() {
+ if s.Kind != SdkSystem || s.ApiLevel.IsPreview() {
return true
}
allowedVersions := ctx.DeviceConfig().PlatformSystemSdkVersions()
@@ -302,7 +272,7 @@
allowedVersions = systemSdkVersions
}
}
- if len(allowedVersions) > 0 && !InList(s.Version.String(), allowedVersions) {
+ if len(allowedVersions) > 0 && !InList(s.ApiLevel.String(), allowedVersions) {
ctx.PropertyErrorf("sdk_version", "incompatible sdk version %q. System SDK version should be one of %q",
s.Raw, allowedVersions)
return false
diff --git a/android/variable.go b/android/variable.go
index dff48c2..e830845 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -331,8 +331,7 @@
VendorVars map[string]map[string]string `json:",omitempty"`
- Ndk_abis *bool `json:",omitempty"`
- Exclude_draft_ndk_apis *bool `json:",omitempty"`
+ Ndk_abis *bool `json:",omitempty"`
Flatten_apex *bool `json:",omitempty"`
ForceApexSymlinkOptimization *bool `json:",omitempty"`
@@ -385,6 +384,8 @@
BuildBrokenTrebleSyspropNeverallow bool `json:",omitempty"`
BuildBrokenVendorPropertyNamespace bool `json:",omitempty"`
+ BuildDebugfsRestrictionsEnabled bool `json:",omitempty"`
+
RequiresInsecureExecmemForSwiftshader bool `json:",omitempty"`
SelinuxIgnoreNeverallows bool `json:",omitempty"`
diff --git a/apex/Android.bp b/apex/Android.bp
index 1890b89..7b52402 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -31,6 +31,7 @@
testSrcs: [
"apex_test.go",
"boot_image_test.go",
+ "platform_bootclasspath_test.go",
"vndk_test.go",
],
pluginFor: ["soong_build"],
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 99cd75e..9fc701d 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -284,7 +284,7 @@
// To install companion files (init_rc, vintf_fragments)
// Copy some common properties of apexBundle to apex_manifest
commonProperties := []string{
- "LOCAL_INIT_RC", "LOCAL_VINTF_FRAGMENTS",
+ "LOCAL_FULL_INIT_RC", "LOCAL_VINTF_FRAGMENTS",
}
for _, name := range commonProperties {
if value, ok := apexAndroidMkData.Entries.EntryMap[name]; ok {
@@ -394,7 +394,7 @@
// Because apex writes .mk with Custom(), we need to write manually some common properties
// which are available via data.Entries
commonProperties := []string{
- "LOCAL_INIT_RC", "LOCAL_VINTF_FRAGMENTS",
+ "LOCAL_FULL_INIT_RC", "LOCAL_VINTF_FRAGMENTS",
"LOCAL_PROPRIETARY_MODULE", "LOCAL_VENDOR_MODULE", "LOCAL_ODM_MODULE", "LOCAL_PRODUCT_MODULE", "LOCAL_SYSTEM_EXT_MODULE",
"LOCAL_MODULE_OWNER",
}
diff --git a/apex/apex.go b/apex/apex.go
index 9d06e1c..f5e6fa9 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -903,7 +903,7 @@
// be built for this apexBundle.
apexInfo := android.ApexInfo{
ApexVariationName: mctx.ModuleName(),
- MinSdkVersionStr: minSdkVersion.String(),
+ MinSdkVersion: minSdkVersion,
RequiredSdks: a.RequiredSdks(),
Updatable: a.Updatable(),
InApexes: []string{mctx.ModuleName()},
@@ -1049,6 +1049,16 @@
if a, ok := mctx.Module().(*apexBundle); ok && !a.vndkApex {
apexBundleName := mctx.ModuleName()
mctx.CreateVariations(apexBundleName)
+ if strings.HasPrefix(apexBundleName, "com.android.art") {
+ // Create an alias from the platform variant. This is done to make
+ // test_for dependencies work for modules that are split by the APEX
+ // mutator, since test_for dependencies always go to the platform variant.
+ // This doesn't happen for normal APEXes that are disjunct, so only do
+ // this for the overlapping ART APEXes.
+ // TODO(b/183882457): Remove this if the test_for functionality is
+ // refactored to depend on the proper APEX variants instead of platform.
+ mctx.CreateAliasVariation("", apexBundleName)
+ }
} else if o, ok := mctx.Module().(*OverrideApex); ok {
apexBundleName := o.GetOverriddenModuleName()
if apexBundleName == "" {
@@ -1056,6 +1066,10 @@
return
}
mctx.CreateVariations(apexBundleName)
+ if strings.HasPrefix(apexBundleName, "com.android.art") {
+ // TODO(b/183882457): See note for CreateAliasVariation above.
+ mctx.CreateAliasVariation("", apexBundleName)
+ }
}
}
@@ -1913,6 +1927,10 @@
filesInfo = append(filesInfo, af)
return true // track transitive dependencies
}
+ } else if rust.IsRlibDepTag(depTag) {
+ // Rlib is statically linked, but it might have shared lib
+ // dependencies. Track them.
+ return true
} else if java.IsbootImageContentDepTag(depTag) {
// Add the contents of the boot image to the apex.
switch child.(type) {
@@ -2254,8 +2272,10 @@
tag := ctx.OtherModuleDependencyTag(module)
switch tag {
case javaLibTag, androidAppTag:
- if m, ok := module.(interface{ CheckStableSdkVersion() error }); ok {
- if err := m.CheckStableSdkVersion(); err != nil {
+ if m, ok := module.(interface {
+ CheckStableSdkVersion(ctx android.BaseModuleContext) error
+ }); ok {
+ if err := m.CheckStableSdkVersion(ctx); err != nil {
ctx.ModuleErrorf("cannot depend on \"%v\": %v", ctx.OtherModuleName(module), err)
}
}
@@ -2925,9 +2945,7 @@
"com.google.android.material_material",
"com.google.android.material_material-nodeps",
- "libatomic",
"libclang_rt",
- "libgcc_stripped",
"libprofile-clang-extras",
"libprofile-clang-extras_ndk",
"libprofile-extras",
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 98b40fd..977a954 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -216,7 +216,7 @@
variables.Platform_sdk_codename = proptools.StringPtr("Q")
variables.Platform_sdk_final = proptools.BoolPtr(false)
variables.Platform_version_active_codenames = []string{"Q"}
- variables.Platform_vndk_version = proptools.StringPtr("VER")
+ variables.Platform_vndk_version = proptools.StringPtr("29")
}),
)
@@ -392,6 +392,15 @@
srcs: ["foo.rs"],
crate_name: "foo",
apex_available: ["myapex"],
+ shared_libs: ["libfoo.shared_from_rust"],
+ }
+
+ cc_library_shared {
+ name: "libfoo.shared_from_rust",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: ["myapex"],
}
rust_library_dylib {
@@ -539,6 +548,7 @@
ensureListContains(t, ctx.ModuleVariantsForTests("libfoo.rlib.rust"), "android_arm64_armv8-a_rlib_dylib-std_apex10000")
ensureListContains(t, ctx.ModuleVariantsForTests("libfoo.dylib.rust"), "android_arm64_armv8-a_dylib_apex10000")
ensureListContains(t, ctx.ModuleVariantsForTests("libbar.ffi"), "android_arm64_armv8-a_shared_apex10000")
+ ensureListContains(t, ctx.ModuleVariantsForTests("libfoo.shared_from_rust"), "android_arm64_armv8-a_shared_apex10000")
// Ensure that both direct and indirect deps are copied into apex
ensureContains(t, copyCmds, "image.apex/lib64/mylib.so")
@@ -548,6 +558,7 @@
ensureContains(t, copyCmds, "image.apex/lib64/libfoo.dylib.rust.dylib.so")
ensureContains(t, copyCmds, "image.apex/lib64/libfoo.ffi.so")
ensureContains(t, copyCmds, "image.apex/lib64/libbar.ffi.so")
+ ensureContains(t, copyCmds, "image.apex/lib64/libfoo.shared_from_rust.so")
// .. but not for java libs
ensureNotContains(t, copyCmds, "image.apex/javalib/myotherjar.jar")
ensureNotContains(t, copyCmds, "image.apex/javalib/msharedjar.jar")
@@ -1366,13 +1377,13 @@
ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"]))
ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libbar.so")
- mylibLdFlags := ctx.ModuleForTests("mylib", "android_vendor.VER_arm64_armv8-a_shared_"+tc.apexVariant).Rule("ld").Args["libFlags"]
- ensureContains(t, mylibLdFlags, "libbar/android_vendor.VER_arm64_armv8-a_shared_"+tc.shouldLink+"/libbar.so")
+ mylibLdFlags := ctx.ModuleForTests("mylib", "android_vendor.29_arm64_armv8-a_shared_"+tc.apexVariant).Rule("ld").Args["libFlags"]
+ ensureContains(t, mylibLdFlags, "libbar/android_vendor.29_arm64_armv8-a_shared_"+tc.shouldLink+"/libbar.so")
for _, ver := range tc.shouldNotLink {
- ensureNotContains(t, mylibLdFlags, "libbar/android_vendor.VER_arm64_armv8-a_shared_"+ver+"/libbar.so")
+ ensureNotContains(t, mylibLdFlags, "libbar/android_vendor.29_arm64_armv8-a_shared_"+ver+"/libbar.so")
}
- mylibCFlags := ctx.ModuleForTests("mylib", "android_vendor.VER_arm64_armv8-a_static_"+tc.apexVariant).Rule("cc").Args["cFlags"]
+ mylibCFlags := ctx.ModuleForTests("mylib", "android_vendor.29_arm64_armv8-a_static_"+tc.apexVariant).Rule("cc").Args["cFlags"]
ver := tc.shouldLink
if tc.shouldLink == "current" {
ver = strconv.Itoa(android.FutureApiLevelInt)
@@ -2411,8 +2422,8 @@
inputsString := strings.Join(inputsList, " ")
// ensure that the apex includes vendor variants of the direct and indirect deps
- ensureContains(t, inputsString, "android_vendor.VER_arm64_armv8-a_shared_apex10000/mylib.so")
- ensureContains(t, inputsString, "android_vendor.VER_arm64_armv8-a_shared_apex10000/mylib2.so")
+ ensureContains(t, inputsString, "android_vendor.29_arm64_armv8-a_shared_apex10000/mylib.so")
+ ensureContains(t, inputsString, "android_vendor.29_arm64_armv8-a_shared_apex10000/mylib2.so")
// ensure that the apex does not include core variants
ensureNotContains(t, inputsString, "android_arm64_armv8-a_shared_apex10000/mylib.so")
@@ -2558,7 +2569,7 @@
}
`)
- vendorVariant := "android_vendor.VER_arm64_armv8-a"
+ vendorVariant := "android_vendor.29_arm64_armv8-a"
ldRule := ctx.ModuleForTests("mybin", vendorVariant+"_apex10000").Rule("ld")
libs := names(ldRule.Args["libFlags"])
@@ -2607,7 +2618,7 @@
)
cflags := strings.Fields(
- ctx.ModuleForTests("foo", "android_product.VER_arm64_armv8-a_apex10000").Rule("cc").Args["cFlags"])
+ ctx.ModuleForTests("foo", "android_product.29_arm64_armv8-a_apex10000").Rule("cc").Args["cFlags"])
ensureListContains(t, cflags, "-D__ANDROID_VNDK__")
ensureListContains(t, cflags, "-D__ANDROID_APEX__")
ensureListContains(t, cflags, "-D__ANDROID_PRODUCT__")
@@ -2745,7 +2756,7 @@
data.Custom(&builder, name, prefix, "", data)
androidMk := builder.String()
ensureContains(t, androidMk, "LOCAL_VINTF_FRAGMENTS := fragment.xml\n")
- ensureContains(t, androidMk, "LOCAL_INIT_RC := init.rc\n")
+ ensureContains(t, androidMk, "LOCAL_FULL_INIT_RC := init.rc\n")
}
func TestStaticLinking(t *testing.T) {
@@ -3305,11 +3316,11 @@
"lib64/libvndk.so",
"lib64/libvndksp.so",
"lib64/libc++.so",
- "etc/llndk.libraries.VER.txt",
- "etc/vndkcore.libraries.VER.txt",
- "etc/vndksp.libraries.VER.txt",
- "etc/vndkprivate.libraries.VER.txt",
- "etc/vndkproduct.libraries.VER.txt",
+ "etc/llndk.libraries.29.txt",
+ "etc/vndkcore.libraries.29.txt",
+ "etc/vndksp.libraries.29.txt",
+ "etc/vndkprivate.libraries.29.txt",
+ "etc/vndkproduct.libraries.29.txt",
})
}
@@ -3495,7 +3506,7 @@
}
}
- assertApexName("com.android.vndk.vVER", "com.android.vndk.current")
+ assertApexName("com.android.vndk.v29", "com.android.vndk.current")
assertApexName("com.android.vndk.v28", "com.android.vndk.v28")
}
@@ -4316,6 +4327,14 @@
}
}
+func TestPrebuiltMissingSrc(t *testing.T) {
+ testApexError(t, `module "myapex" variant "android_common".*: prebuilt_apex does not support "arm64_armv8-a"`, `
+ prebuilt_apex {
+ name: "myapex",
+ }
+ `)
+}
+
func TestPrebuiltFilenameOverride(t *testing.T) {
ctx := testApex(t, `
prebuilt_apex {
@@ -4356,9 +4375,7 @@
// These tests verify that the prebuilt_apex/deapexer to java_import wiring allows for the
// propagation of paths to dex implementation jars from the former to the latter.
func TestPrebuiltExportDexImplementationJars(t *testing.T) {
- transform := func(config *dexpreopt.GlobalConfig) {
- // Empty transformation.
- }
+ transform := android.NullFixturePreparer
checkDexJarBuildPath := func(t *testing.T, ctx *android.TestContext, name string) {
// Make sure the import has been given the correct path to the dex jar.
@@ -4528,9 +4545,7 @@
}
func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) {
- transform := func(config *dexpreopt.GlobalConfig) {
- config.BootJars = android.CreateTestConfiguredJarList([]string{"myapex:libfoo", "myapex:libbar"})
- }
+ preparer := java.FixtureConfigureBootJars("myapex:libfoo", "myapex:libbar")
checkBootDexJarPath := func(t *testing.T, ctx *android.TestContext, stem string, bootDexJarPath string) {
t.Helper()
@@ -4551,8 +4566,8 @@
checkHiddenAPIIndexInputs := func(t *testing.T, ctx *android.TestContext, expectedInputs string) {
t.Helper()
- hiddenAPIIndex := ctx.SingletonForTests("hiddenapi_index")
- indexRule := hiddenAPIIndex.Rule("singleton-merged-hiddenapi-index")
+ platformBootclasspath := ctx.ModuleForTests("platform-bootclasspath", "android_common")
+ indexRule := platformBootclasspath.Rule("platform-bootclasspath-monolithic-hiddenapi-index")
java.CheckHiddenAPIRuleInputs(t, expectedInputs, indexRule)
}
@@ -4586,7 +4601,7 @@
}
`
- ctx := testDexpreoptWithApexes(t, bp, "", transform)
+ ctx := testDexpreoptWithApexes(t, bp, "", preparer)
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")
@@ -4597,6 +4612,40 @@
`)
})
+ t.Run("apex_set only", func(t *testing.T) {
+ bp := `
+ apex_set {
+ name: "myapex",
+ set: "myapex.apks",
+ exported_java_libs: ["libfoo", "libbar"],
+ }
+
+ java_import {
+ name: "libfoo",
+ jars: ["libfoo.jar"],
+ apex_available: ["myapex"],
+ }
+
+ java_sdk_library_import {
+ name: "libbar",
+ public: {
+ jars: ["libbar.jar"],
+ },
+ apex_available: ["myapex"],
+ }
+ `
+
+ ctx := testDexpreoptWithApexes(t, bp, "", preparer)
+ 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.
+ checkHiddenAPIIndexInputs(t, ctx, `
+.intermediates/libbar/android_common_myapex/hiddenapi/index.csv
+.intermediates/libfoo/android_common_myapex/hiddenapi/index.csv
+`)
+ })
+
t.Run("prebuilt with source library preferred", func(t *testing.T) {
bp := `
prebuilt_apex {
@@ -4645,7 +4694,7 @@
// prebuilt_apex module always depends on the prebuilt, and so it doesn't
// find the dex boot jar in it. We either need to disable the source libfoo
// or make the prebuilt libfoo preferred.
- testDexpreoptWithApexes(t, bp, "failed to find a dex jar path for module 'libfoo'", transform)
+ testDexpreoptWithApexes(t, bp, "failed to find a dex jar path for module 'libfoo'", preparer)
})
t.Run("prebuilt library preferred with source", func(t *testing.T) {
@@ -4693,7 +4742,7 @@
}
`
- ctx := testDexpreoptWithApexes(t, bp, "", transform)
+ ctx := testDexpreoptWithApexes(t, bp, "", preparer)
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")
@@ -4760,7 +4809,7 @@
}
`
- ctx := testDexpreoptWithApexes(t, bp, "", transform)
+ ctx := testDexpreoptWithApexes(t, bp, "", preparer)
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")
@@ -4777,7 +4826,7 @@
name: "myapex",
enabled: false,
key: "myapex.key",
- java_libs: ["libfoo"],
+ java_libs: ["libfoo", "libbar"],
}
apex_key {
@@ -4829,14 +4878,14 @@
}
`
- ctx := testDexpreoptWithApexes(t, bp, "", transform)
+ ctx := testDexpreoptWithApexes(t, bp, "", preparer)
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.
checkHiddenAPIIndexInputs(t, ctx, `
-.intermediates/prebuilt_libbar/android_common_prebuilt_myapex/hiddenapi/index.csv
-.intermediates/prebuilt_libfoo/android_common_prebuilt_myapex/hiddenapi/index.csv
+.intermediates/prebuilt_libbar/android_common_myapex/hiddenapi/index.csv
+.intermediates/prebuilt_libfoo/android_common_myapex/hiddenapi/index.csv
`)
})
}
@@ -6360,8 +6409,7 @@
}
func TestAppSetBundlePrebuilt(t *testing.T) {
- ctx := testApex(t, "", android.FixtureModifyMockFS(func(fs android.MockFS) {
- bp := `
+ bp := `
apex_set {
name: "myapex",
filename: "foo_v2.apex",
@@ -6369,27 +6417,26 @@
none: { set: "myapex.apks", },
hwaddress: { set: "myapex.hwasan.apks", },
},
- }`
- fs["Android.bp"] = []byte(bp)
- }),
- prepareForTestWithSantitizeHwaddress,
- )
+ }
+ `
+ ctx := testApex(t, bp, prepareForTestWithSantitizeHwaddress)
- m := ctx.ModuleForTests("myapex", "android_common")
- extractedApex := m.Output("out/soong/.intermediates/myapex/android_common/foo_v2.apex")
+ // Check that the extractor produces the correct output file from the correct input file.
+ extractorOutput := "out/soong/.intermediates/myapex.apex.extractor/android_common/extracted/myapex.hwasan.apks"
- actual := extractedApex.Inputs
- if len(actual) != 1 {
- t.Errorf("expected a single input")
- }
+ m := ctx.ModuleForTests("myapex.apex.extractor", "android_common")
+ extractedApex := m.Output(extractorOutput)
- expected := "myapex.hwasan.apks"
- if actual[0].String() != expected {
- t.Errorf("expected %s, got %s", expected, actual[0].String())
- }
+ android.AssertArrayString(t, "extractor input", []string{"myapex.hwasan.apks"}, extractedApex.Inputs.Strings())
+
+ // Ditto for the apex.
+ m = ctx.ModuleForTests("myapex", "android_common")
+ copiedApex := m.Output("out/soong/.intermediates/myapex/android_common/foo_v2.apex")
+
+ android.AssertStringEquals(t, "myapex input", extractorOutput, copiedApex.Input.String())
}
-func testNoUpdatableJarsInBootImage(t *testing.T, errmsg string, transformDexpreoptConfig func(*dexpreopt.GlobalConfig)) {
+func testNoUpdatableJarsInBootImage(t *testing.T, errmsg string, preparer android.FixturePreparer) {
t.Helper()
bp := `
@@ -6477,10 +6524,10 @@
}
`
- testDexpreoptWithApexes(t, bp, errmsg, transformDexpreoptConfig)
+ testDexpreoptWithApexes(t, bp, errmsg, preparer)
}
-func testDexpreoptWithApexes(t *testing.T, bp, errmsg string, transformDexpreoptConfig func(*dexpreopt.GlobalConfig)) *android.TestContext {
+func testDexpreoptWithApexes(t *testing.T, bp, errmsg string, preparer android.FixturePreparer) *android.TestContext {
t.Helper()
fs := android.MockFS{
@@ -6506,18 +6553,13 @@
java.PrepareForTestWithJavaDefaultModules,
java.PrepareForTestWithJavaSdkLibraryFiles,
PrepareForTestWithApexBuildComponents,
- android.FixtureModifyConfig(func(config android.Config) {
- pathCtx := android.PathContextForTesting(config)
- dexpreoptConfig := dexpreopt.GlobalConfigForTests(pathCtx)
- transformDexpreoptConfig(dexpreoptConfig)
- dexpreopt.SetTestGlobalConfig(config, dexpreoptConfig)
-
- // Make sure that any changes to these dexpreopt properties are mirrored in the corresponding
- // product variables.
- config.TestProductVariables.BootJars = dexpreoptConfig.BootJars
- config.TestProductVariables.UpdatableBootJars = dexpreoptConfig.UpdatableBootJars
- }),
+ preparer,
fs.AddToFixture(),
+ android.FixtureAddTextFile("frameworks/base/boot/Android.bp", `
+ platform_bootclasspath {
+ name: "platform-bootclasspath",
+ }
+ `),
).
ExtendWithErrorHandler(errorHandler).
RunTestWithBp(t, bp)
@@ -6557,92 +6599,95 @@
}
func TestNoUpdatableJarsInBootImage(t *testing.T) {
- var err string
- var transform func(*dexpreopt.GlobalConfig)
+ // Set the BootJars in dexpreopt.GlobalConfig and productVariables to the same value. This can
+ // result in an invalid configuration as it does not set the ArtApexJars and allows art apex
+ // modules to be included in the BootJars.
+ prepareSetBootJars := func(bootJars ...string) android.FixturePreparer {
+ return android.GroupFixturePreparers(
+ dexpreopt.FixtureSetBootJars(bootJars...),
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.BootJars = android.CreateTestConfiguredJarList(bootJars)
+ }),
+ )
+ }
+
+ // Set the ArtApexJars and BootJars in dexpreopt.GlobalConfig and productVariables all to the
+ // same value. This can result in an invalid configuration as it allows non art apex jars to be
+ // specified in the ArtApexJars configuration.
+ prepareSetArtJars := func(bootJars ...string) android.FixturePreparer {
+ return android.GroupFixturePreparers(
+ dexpreopt.FixtureSetArtBootJars(bootJars...),
+ dexpreopt.FixtureSetBootJars(bootJars...),
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.BootJars = android.CreateTestConfiguredJarList(bootJars)
+ }),
+ )
+ }
t.Run("updatable jar from ART apex in the ART boot image => ok", func(t *testing.T) {
- transform = func(config *dexpreopt.GlobalConfig) {
- config.ArtApexJars = android.CreateTestConfiguredJarList([]string{"com.android.art.debug:some-art-lib"})
- }
- testNoUpdatableJarsInBootImage(t, "", transform)
+ preparer := java.FixtureConfigureBootJars("com.android.art.debug:some-art-lib")
+ testNoUpdatableJarsInBootImage(t, "", preparer)
})
t.Run("updatable jar from ART apex in the framework boot image => error", func(t *testing.T) {
- err = `module "some-art-lib" from updatable apexes \["com.android.art.debug"\] is not allowed in the framework boot image`
- transform = func(config *dexpreopt.GlobalConfig) {
- config.BootJars = android.CreateTestConfiguredJarList([]string{"com.android.art.debug:some-art-lib"})
- }
- testNoUpdatableJarsInBootImage(t, err, transform)
+ err := `module "some-art-lib" from updatable apexes \["com.android.art.debug"\] is not allowed in the framework boot image`
+ // Update the dexpreopt BootJars directly.
+ preparer := prepareSetBootJars("com.android.art.debug:some-art-lib")
+ testNoUpdatableJarsInBootImage(t, err, preparer)
})
t.Run("updatable jar from some other apex in the ART boot image => error", func(t *testing.T) {
- err = `module "some-updatable-apex-lib" from updatable apexes \["some-updatable-apex"\] is not allowed in the ART boot image`
- transform = func(config *dexpreopt.GlobalConfig) {
- config.ArtApexJars = android.CreateTestConfiguredJarList([]string{"some-updatable-apex:some-updatable-apex-lib"})
- }
- testNoUpdatableJarsInBootImage(t, err, transform)
+ err := `module "some-updatable-apex-lib" from updatable apexes \["some-updatable-apex"\] is not allowed in the ART boot image`
+ // Update the dexpreopt ArtApexJars directly.
+ preparer := prepareSetArtJars("some-updatable-apex:some-updatable-apex-lib")
+ testNoUpdatableJarsInBootImage(t, err, preparer)
})
t.Run("non-updatable jar from some other apex in the ART boot image => error", func(t *testing.T) {
- err = `module "some-non-updatable-apex-lib" is not allowed in the ART boot image`
- transform = func(config *dexpreopt.GlobalConfig) {
- config.ArtApexJars = android.CreateTestConfiguredJarList([]string{"some-non-updatable-apex:some-non-updatable-apex-lib"})
- }
- testNoUpdatableJarsInBootImage(t, err, transform)
+ err := `module "some-non-updatable-apex-lib" is not allowed in the ART boot image`
+ // Update the dexpreopt ArtApexJars directly.
+ preparer := prepareSetArtJars("some-non-updatable-apex:some-non-updatable-apex-lib")
+ testNoUpdatableJarsInBootImage(t, err, preparer)
})
t.Run("updatable jar from some other apex in the framework boot image => error", func(t *testing.T) {
- err = `module "some-updatable-apex-lib" from updatable apexes \["some-updatable-apex"\] is not allowed in the framework boot image`
- transform = func(config *dexpreopt.GlobalConfig) {
- config.BootJars = android.CreateTestConfiguredJarList([]string{"some-updatable-apex:some-updatable-apex-lib"})
- }
- testNoUpdatableJarsInBootImage(t, err, transform)
+ err := `module "some-updatable-apex-lib" from updatable apexes \["some-updatable-apex"\] is not allowed in the framework boot image`
+ preparer := java.FixtureConfigureBootJars("some-updatable-apex:some-updatable-apex-lib")
+ testNoUpdatableJarsInBootImage(t, err, preparer)
})
t.Run("non-updatable jar from some other apex in the framework boot image => ok", func(t *testing.T) {
- transform = func(config *dexpreopt.GlobalConfig) {
- config.BootJars = android.CreateTestConfiguredJarList([]string{"some-non-updatable-apex:some-non-updatable-apex-lib"})
- }
- testNoUpdatableJarsInBootImage(t, "", transform)
+ preparer := java.FixtureConfigureBootJars("some-non-updatable-apex:some-non-updatable-apex-lib")
+ testNoUpdatableJarsInBootImage(t, "", preparer)
})
t.Run("nonexistent jar in the ART boot image => error", func(t *testing.T) {
- err = "failed to find a dex jar path for module 'nonexistent'"
- transform = func(config *dexpreopt.GlobalConfig) {
- config.ArtApexJars = android.CreateTestConfiguredJarList([]string{"platform:nonexistent"})
- }
- testNoUpdatableJarsInBootImage(t, err, transform)
+ err := `"platform-bootclasspath" depends on undefined module "nonexistent"`
+ preparer := java.FixtureConfigureBootJars("platform:nonexistent")
+ testNoUpdatableJarsInBootImage(t, err, preparer)
})
t.Run("nonexistent jar in the framework boot image => error", func(t *testing.T) {
- err = "failed to find a dex jar path for module 'nonexistent'"
- transform = func(config *dexpreopt.GlobalConfig) {
- config.BootJars = android.CreateTestConfiguredJarList([]string{"platform:nonexistent"})
- }
- testNoUpdatableJarsInBootImage(t, err, transform)
+ err := `"platform-bootclasspath" depends on undefined module "nonexistent"`
+ preparer := java.FixtureConfigureBootJars("platform:nonexistent")
+ testNoUpdatableJarsInBootImage(t, err, preparer)
})
t.Run("platform jar in the ART boot image => error", func(t *testing.T) {
- err = `module "some-platform-lib" is not allowed in the ART boot image`
- transform = func(config *dexpreopt.GlobalConfig) {
- config.ArtApexJars = android.CreateTestConfiguredJarList([]string{"platform:some-platform-lib"})
- }
- testNoUpdatableJarsInBootImage(t, err, transform)
+ err := `module "some-platform-lib" is not allowed in the ART boot image`
+ // Update the dexpreopt ArtApexJars directly.
+ preparer := prepareSetArtJars("platform:some-platform-lib")
+ testNoUpdatableJarsInBootImage(t, err, preparer)
})
t.Run("platform jar in the framework boot image => ok", func(t *testing.T) {
- transform = func(config *dexpreopt.GlobalConfig) {
- config.BootJars = android.CreateTestConfiguredJarList([]string{"platform:some-platform-lib"})
- }
- testNoUpdatableJarsInBootImage(t, "", transform)
+ preparer := java.FixtureConfigureBootJars("platform:some-platform-lib")
+ testNoUpdatableJarsInBootImage(t, "", preparer)
})
-
}
func TestDexpreoptAccessDexFilesFromPrebuiltApex(t *testing.T) {
- transform := func(config *dexpreopt.GlobalConfig) {
- config.BootJars = android.CreateTestConfiguredJarList([]string{"myapex:libfoo"})
- }
+ preparer := java.FixtureConfigureBootJars("myapex:libfoo")
t.Run("prebuilt no source", func(t *testing.T) {
testDexpreoptWithApexes(t, `
prebuilt_apex {
@@ -6662,7 +6707,7 @@
name: "libfoo",
jars: ["libfoo.jar"],
}
-`, "", transform)
+`, "", preparer)
})
t.Run("prebuilt no source", func(t *testing.T) {
@@ -6684,7 +6729,7 @@
name: "libfoo",
jars: ["libfoo.jar"],
}
-`, "", transform)
+`, "", preparer)
})
}
@@ -6947,6 +6992,56 @@
ensureLinkedLibIs("myprivlib", "android_arm64_armv8-a_shared", "out/soong/.intermediates/mylib/", "android_arm64_armv8-a_shared/mylib.so")
}
+func TestTestForForLibInOtherApex(t *testing.T) {
+ // This case is only allowed for known overlapping APEXes, i.e. the ART APEXes.
+ _ = testApex(t, `
+ apex {
+ name: "com.android.art",
+ key: "myapex.key",
+ native_shared_libs: ["mylib"],
+ updatable: false,
+ }
+
+ apex {
+ name: "com.android.art.debug",
+ key: "myapex.key",
+ native_shared_libs: ["mylib", "mytestlib"],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ stubs: {
+ versions: ["1"],
+ },
+ apex_available: ["com.android.art", "com.android.art.debug"],
+ }
+
+ cc_library {
+ name: "mytestlib",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ shared_libs: ["mylib"],
+ stl: "none",
+ apex_available: ["com.android.art.debug"],
+ test_for: ["com.android.art"],
+ }
+ `,
+ android.MockFS{
+ "system/sepolicy/apex/com.android.art-file_contexts": nil,
+ "system/sepolicy/apex/com.android.art.debug-file_contexts": nil,
+ }.AddToFixture())
+}
+
// TODO(jungjw): Move this to proptools
func intPtr(i int) *int {
return &i
@@ -6972,10 +7067,10 @@
}),
)
- m := ctx.ModuleForTests("myapex", "android_common")
+ m := ctx.ModuleForTests("myapex.apex.extractor", "android_common")
// Check extract_apks tool parameters.
- extractedApex := m.Output("out/soong/.intermediates/myapex/android_common/foo_v2.apex")
+ extractedApex := m.Output("extracted/myapex.apks")
actual := extractedApex.Args["abis"]
expected := "ARMEABI_V7A,ARM64_V8A"
if actual != expected {
@@ -6987,6 +7082,7 @@
t.Errorf("Unexpected abis parameter - expected %q vs actual %q", expected, actual)
}
+ m = ctx.ModuleForTests("myapex", "android_common")
a := m.Module().(*ApexSet)
expectedOverrides := []string{"foo"}
actualOverrides := android.AndroidMkEntriesForTest(t, ctx, a)[0].EntryMap["LOCAL_OVERRIDES_MODULES"]
diff --git a/apex/boot_image_test.go b/apex/boot_image_test.go
index 574166a..d447d70 100644
--- a/apex/boot_image_test.go
+++ b/apex/boot_image_test.go
@@ -19,7 +19,6 @@
"testing"
"android/soong/android"
- "android/soong/dexpreopt"
"android/soong/java"
)
@@ -42,8 +41,7 @@
result := android.GroupFixturePreparers(
prepareForTestWithBootImage,
// Configure some libraries in the art and framework boot images.
- dexpreopt.FixtureSetArtBootJars("com.android.art:baz", "com.android.art:quuz"),
- dexpreopt.FixtureSetBootJars("platform:foo", "platform:bar"),
+ java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz", "platform:foo", "platform:bar"),
prepareForTestWithArtApex,
java.PrepareForTestWithJavaSdkLibraryFiles,
@@ -169,7 +167,7 @@
prepareForTestWithArtApex,
// Configure some libraries in the art boot image.
- dexpreopt.FixtureSetArtBootJars("com.android.art:foo", "com.android.art:bar"),
+ java.FixtureConfigureBootJars("com.android.art:foo", "com.android.art:bar"),
).RunTestWithBp(t, `
apex {
name: "com.android.art",
@@ -264,7 +262,7 @@
}),
// Configure some libraries in the art boot image.
- dexpreopt.FixtureSetArtBootJars("com.android.art:foo", "com.android.art:bar"),
+ java.FixtureConfigureBootJars("com.android.art:foo", "com.android.art:bar"),
).RunTestWithBp(t, `
prebuilt_apex {
name: "com.android.art",
@@ -305,6 +303,7 @@
`)
java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common", []string{
+ `com.android.art.apex.selector`,
`prebuilt_bar`,
`prebuilt_foo`,
})
diff --git a/apex/builder.go b/apex/builder.go
index 2df380b..e59dc96 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -517,6 +517,9 @@
outHostBinDir := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "bin").String()
prebuiltSdkToolsBinDir := filepath.Join("prebuilts", "sdk", "tools", runtime.GOOS, "bin")
+ // Figure out if need to compress apex.
+ compressionEnabled := ctx.Config().CompressedApex() && proptools.BoolDefault(a.properties.Compressible, false) && !a.testApex
+
if apexType == imageApex {
////////////////////////////////////////////////////////////////////////////////////
// Step 2: create canned_fs_config which encodes filemode,uid,gid of each files
@@ -631,7 +634,7 @@
ctx.PropertyErrorf("test_only_no_hashtree", "not available")
return
}
- if moduleMinSdkVersion.GreaterThan(android.SdkVersion_Android10) || a.testOnlyShouldSkipHashtreeGeneration() {
+ if (moduleMinSdkVersion.GreaterThan(android.SdkVersion_Android10) || a.testOnlyShouldSkipHashtreeGeneration()) && !compressionEnabled {
// Apexes which are supposed to be installed in builtin dirs(/system, etc)
// don't need hashtree for activation. Therefore, by removing hashtree from
// apex bundle (filesystem image in it, to be specific), we can save storage.
@@ -780,12 +783,11 @@
})
a.outputFile = signedOutputFile
- // Process APEX compression if enabled or forced
if ctx.ModuleDir() != "system/apex/apexd/apexd_testdata" && a.testOnlyShouldForceCompression() {
ctx.PropertyErrorf("test_only_force_compression", "not available")
return
}
- compressionEnabled := ctx.Config().CompressedApex() && proptools.BoolDefault(a.properties.Compressible, false)
+
if apexType == imageApex && (compressionEnabled || a.testOnlyShouldForceCompression()) {
a.isCompressed = true
unsignedCompressedOutputFile := android.PathForModuleOut(ctx, a.Name()+".capex.unsigned")
@@ -946,16 +948,19 @@
depInfos[to.Name()] = info
} else {
toMinSdkVersion := "(no version)"
- if m, ok := to.(interface{ MinSdkVersion() string }); ok {
+ if m, ok := to.(interface {
+ MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec
+ }); ok {
+ if v := m.MinSdkVersion(ctx); !v.ApiLevel.IsNone() {
+ toMinSdkVersion = v.ApiLevel.String()
+ }
+ } else if m, ok := to.(interface{ MinSdkVersion() string }); ok {
+ // TODO(b/175678607) eliminate the use of MinSdkVersion returning
+ // string
if v := m.MinSdkVersion(); v != "" {
toMinSdkVersion = v
}
- } else if m, ok := to.(interface{ MinSdkVersionString() string }); ok {
- if v := m.MinSdkVersionString(); v != "" {
- toMinSdkVersion = v
- }
}
-
depInfos[to.Name()] = android.ApexModuleDepInfo{
To: to.Name(),
From: []string{from.Name()},
diff --git a/apex/deapexer.go b/apex/deapexer.go
index 46ce41f..1db13f9 100644
--- a/apex/deapexer.go
+++ b/apex/deapexer.go
@@ -49,35 +49,31 @@
Exported_java_libs []string
}
+type SelectedApexProperties struct {
+ // The path to the apex selected for use by this module.
+ //
+ // Is tagged as `android:"path"` because it will usually contain a string of the form ":<module>"
+ // and is tagged as "`blueprint:"mutate"` because it is only initialized in a LoadHook not an
+ // Android.bp file.
+ Selected_apex *string `android:"path" blueprint:"mutated"`
+}
+
type Deapexer struct {
android.ModuleBase
- prebuilt android.Prebuilt
- properties DeapexerProperties
- apexFileProperties ApexFileProperties
+ properties DeapexerProperties
+ selectedApexProperties SelectedApexProperties
inputApex android.Path
}
func privateDeapexerFactory() android.Module {
module := &Deapexer{}
- module.AddProperties(
- &module.properties,
- &module.apexFileProperties,
- )
- android.InitPrebuiltModuleWithSrcSupplier(module, module.apexFileProperties.prebuiltApexSelector, "src")
+ module.AddProperties(&module.properties, &module.selectedApexProperties)
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
return module
}
-func (p *Deapexer) Prebuilt() *android.Prebuilt {
- return &p.prebuilt
-}
-
-func (p *Deapexer) Name() string {
- return p.prebuilt.Name(p.ModuleBase.Name())
-}
-
func (p *Deapexer) DepsMutator(ctx android.BottomUpMutatorContext) {
// Add dependencies from the java modules to which this exports files from the `.apex` file onto
// this module so that they can access the `DeapexerInfo` object that this provides.
@@ -88,7 +84,7 @@
}
func (p *Deapexer) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- p.inputApex = p.Prebuilt().SingleSourcePath(ctx)
+ p.inputApex = android.OptionalPathForModuleSrc(ctx, p.selectedApexProperties.Selected_apex).Path()
// Create and remember the directory into which the .apex file's contents will be unpacked.
deapexerOutput := android.PathForModuleOut(ctx, "deapexer")
diff --git a/apex/platform_bootclasspath_test.go b/apex/platform_bootclasspath_test.go
new file mode 100644
index 0000000..74830d3
--- /dev/null
+++ b/apex/platform_bootclasspath_test.go
@@ -0,0 +1,175 @@
+// 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"
+ "github.com/google/blueprint"
+)
+
+// Contains tests for platform_bootclasspath logic from java/platform_bootclasspath.go that requires
+// apexes.
+
+var prepareForTestWithPlatformBootclasspath = android.GroupFixturePreparers(
+ java.PrepareForTestWithDexpreopt,
+ PrepareForTestWithApexBuildComponents,
+)
+
+func TestPlatformBootclasspathDependencies(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForTestWithPlatformBootclasspath,
+ prepareForTestWithArtApex,
+ prepareForTestWithMyapex,
+ // Configure some libraries in the art and framework boot images.
+ java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz", "platform:foo"),
+ java.FixtureConfigureUpdatableBootJars("myapex:bar"),
+ java.PrepareForTestWithJavaSdkLibraryFiles,
+ java.FixtureWithLastReleaseApis("foo"),
+ ).RunTestWithBp(t, `
+ 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",
+ }
+
+ bootclasspath_fragment {
+ name: "art-bootclasspath-fragment",
+ apex_available: [
+ "com.android.art",
+ ],
+ contents: [
+ "baz",
+ "quuz",
+ ],
+ }
+
+ java_library {
+ name: "baz",
+ apex_available: [
+ "com.android.art",
+ ],
+ srcs: ["b.java"],
+ installable: true,
+ }
+
+ // Add a java_import that is not preferred and so won't have an appropriate apex variant created
+ // for it to make sure that the platform_bootclasspath doesn't try and add a dependency onto it.
+ java_import {
+ name: "baz",
+ apex_available: [
+ "com.android.art",
+ ],
+ jars: ["b.jar"],
+ }
+
+ java_library {
+ name: "quuz",
+ apex_available: [
+ "com.android.art",
+ ],
+ srcs: ["b.java"],
+ installable: true,
+ }
+
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ java_libs: [
+ "bar",
+ ],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ java_sdk_library {
+ name: "foo",
+ srcs: ["b.java"],
+ }
+
+ java_library {
+ name: "bar",
+ srcs: ["b.java"],
+ installable: true,
+ apex_available: ["myapex"],
+ permitted_packages: ["bar"],
+ }
+
+ platform_bootclasspath {
+ name: "myplatform-bootclasspath",
+
+ fragments: [
+ {
+ apex: "com.android.art",
+ module: "art-bootclasspath-fragment",
+ },
+ ],
+ }
+`,
+ )
+
+ java.CheckPlatformBootclasspathModules(t, result, "myplatform-bootclasspath", []string{
+ "com.android.art:baz",
+ "com.android.art:quuz",
+ "platform:foo",
+ "myapex:bar",
+ })
+
+ java.CheckPlatformBootclasspathFragments(t, result, "myplatform-bootclasspath", []string{
+ `com.android.art:art-bootclasspath-fragment`,
+ })
+
+ // Make sure that the myplatform-bootclasspath has the correct dependencies.
+ CheckModuleDependencies(t, result.TestContext, "myplatform-bootclasspath", "android_common", []string{
+ `platform:dex2oatd`,
+ `com.android.art:baz`,
+ `com.android.art:quuz`,
+ `platform:foo`,
+ `myapex:bar`,
+ `com.android.art:art-bootclasspath-fragment`,
+ })
+}
+
+// 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
+// name of the apex, or platform is it is not part of an apex and <module> is the module name.
+func CheckModuleDependencies(t *testing.T, ctx *android.TestContext, name, variant string, expected []string) {
+ t.Helper()
+ module := ctx.ModuleForTests(name, variant).Module()
+ modules := []android.Module{}
+ ctx.VisitDirectDeps(module, func(m blueprint.Module) {
+ modules = append(modules, m.(android.Module))
+ })
+
+ pairs := java.ApexNamePairsFromModules(ctx, modules)
+ android.AssertDeepEquals(t, "module dependencies", expected, pairs)
+}
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 3280cd8..a9d24a7 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -48,6 +48,9 @@
type prebuiltCommon struct {
prebuilt android.Prebuilt
properties prebuiltCommonProperties
+
+ deapexerProperties DeapexerProperties
+ selectedApexProperties SelectedApexProperties
}
type sanitizedPrebuilt interface {
@@ -91,11 +94,130 @@
return false
}
+func (p *prebuiltCommon) deapexerDeps(ctx android.BottomUpMutatorContext) {
+ // Add dependencies onto the java modules that represent the java libraries that are provided by
+ // and exported from this prebuilt apex.
+ for _, lib := range p.deapexerProperties.Exported_java_libs {
+ dep := prebuiltApexExportedModuleName(ctx, lib)
+ ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(), exportedJavaLibTag, dep)
+ }
+}
+
+// apexInfoMutator marks any modules for which this apex exports a file as requiring an apex
+// specific variant and checks that they are supported.
+//
+// The apexMutator will ensure that the ApexInfo objects passed to BuildForApex(ApexInfo) are
+// associated with the apex specific variant using the ApexInfoProvider for later retrieval.
+//
+// Unlike the source apex module type the prebuilt_apex module type cannot share compatible variants
+// across prebuilt_apex modules. That is because there is no way to determine whether two
+// prebuilt_apex modules that export files for the same module are compatible. e.g. they could have
+// been built from different source at different times or they could have been built with different
+// build options that affect the libraries.
+//
+// While it may be possible to provide sufficient information to determine whether two prebuilt_apex
+// modules were compatible it would be a lot of work and would not provide much benefit for a couple
+// of reasons:
+// * The number of prebuilt_apex modules that will be exporting files for the same module will be
+// low as the prebuilt_apex only exports files for the direct dependencies that require it and
+// very few modules are direct dependencies of multiple prebuilt_apex modules, e.g. there are a
+// few com.android.art* apex files that contain the same contents and could export files for the
+// same modules but only one of them needs to do so. Contrast that with source apex modules which
+// need apex specific variants for every module that contributes code to the apex, whether direct
+// or indirect.
+// * The build cost of a prebuilt_apex variant is generally low as at worst it will involve some
+// extra copying of files. Contrast that with source apex modules that has to build each variant
+// from source.
+func (p *prebuiltCommon) apexInfoMutator(mctx android.TopDownMutatorContext) {
+
+ // Collect direct dependencies into contents.
+ contents := make(map[string]android.ApexMembership)
+
+ // Collect the list of dependencies.
+ var dependencies []android.ApexModule
+ mctx.VisitDirectDeps(func(m android.Module) {
+ tag := mctx.OtherModuleDependencyTag(m)
+ if tag == exportedJavaLibTag {
+ depName := mctx.OtherModuleName(m)
+
+ // It is an error if the other module is not a prebuilt.
+ if _, ok := m.(android.PrebuiltInterface); !ok {
+ mctx.PropertyErrorf("exported_java_libs", "%q is not a prebuilt module", depName)
+ return
+ }
+
+ // It is an error if the other module is not an ApexModule.
+ if _, ok := m.(android.ApexModule); !ok {
+ mctx.PropertyErrorf("exported_java_libs", "%q is not usable within an apex", depName)
+ return
+ }
+
+ // Strip off the prebuilt_ prefix if present before storing content to ensure consistent
+ // behavior whether there is a corresponding source module present or not.
+ depName = android.RemoveOptionalPrebuiltPrefix(depName)
+
+ // Remember that this module was added as a direct dependency.
+ contents[depName] = contents[depName].Add(true)
+
+ // Add the module to the list of dependencies that need to have an APEX variant.
+ dependencies = append(dependencies, m.(android.ApexModule))
+ }
+ })
+
+ // Create contents for the prebuilt_apex and store it away for later use.
+ apexContents := android.NewApexContents(contents)
+ mctx.SetProvider(ApexBundleInfoProvider, ApexBundleInfo{
+ Contents: apexContents,
+ })
+
+ // Create an ApexInfo for the prebuilt_apex.
+ apexInfo := android.ApexInfo{
+ ApexVariationName: android.RemoveOptionalPrebuiltPrefix(mctx.ModuleName()),
+ InApexes: []string{mctx.ModuleName()},
+ ApexContents: []*android.ApexContents{apexContents},
+ ForPrebuiltApex: true,
+ }
+
+ // Mark the dependencies of this module as requiring a variant for this module.
+ for _, am := range dependencies {
+ am.BuildForApex(apexInfo)
+ }
+}
+
+// prebuiltApexSelectorModule is a private module type that is only created by the prebuilt_apex
+// module. It selects the apex to use and makes it available for use by prebuilt_apex and the
+// deapexer.
+type prebuiltApexSelectorModule struct {
+ android.ModuleBase
+
+ apexFileProperties ApexFileProperties
+
+ inputApex android.Path
+}
+
+func privateApexSelectorModuleFactory() android.Module {
+ module := &prebuiltApexSelectorModule{}
+ module.AddProperties(
+ &module.apexFileProperties,
+ )
+ android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ return module
+}
+
+func (p *prebuiltApexSelectorModule) Srcs() android.Paths {
+ return android.Paths{p.inputApex}
+}
+
+func (p *prebuiltApexSelectorModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ p.inputApex = android.SingleSourcePathFromSupplier(ctx, p.apexFileProperties.prebuiltApexSelector, "src")
+}
+
type Prebuilt struct {
android.ModuleBase
prebuiltCommon
- properties PrebuiltProperties
+ properties PrebuiltProperties
+ selectedApexProperties SelectedApexProperties
inputApex android.Path
installDir android.InstallPath
@@ -113,19 +235,19 @@
// This cannot be marked as `android:"arch_variant"` because the `prebuilt_apex` is only mutated
// for android_common. That is so that it will have the same arch variant as, and so be compatible
// with, the source `apex` module type that it replaces.
- Src *string
+ Src *string `android:"path"`
Arch struct {
Arm struct {
- Src *string
+ Src *string `android:"path"`
}
Arm64 struct {
- Src *string
+ Src *string `android:"path"`
}
X86 struct {
- Src *string
+ Src *string `android:"path"`
}
X86_64 struct {
- Src *string
+ Src *string `android:"path"`
}
}
}
@@ -152,20 +274,22 @@
src = String(p.Arch.X86.Src)
case android.X86_64:
src = String(p.Arch.X86_64.Src)
- default:
- ctx.OtherModuleErrorf(prebuilt, "prebuilt_apex does not support %q", multiTargets[0].Arch.String())
- return nil
}
if src == "" {
src = String(p.Src)
}
+ if src == "" {
+ ctx.OtherModuleErrorf(prebuilt, "prebuilt_apex does not support %q", multiTargets[0].Arch.String())
+ // Drop through to return an empty string as the src (instead of nil) to avoid the prebuilt
+ // logic from reporting a more general, less useful message.
+ }
+
return []string{src}
}
type PrebuiltProperties struct {
ApexFileProperties
- DeapexerProperties
Installable *bool
// Optional name for the installed apex. If unspecified, name of the
@@ -221,28 +345,77 @@
// 3. The `deapexer` module adds a dependency from the modules that require the exported files onto
// itself so that they can retrieve the file paths to those files.
//
+// It also creates a child module `selector` that is responsible for selecting the appropriate
+// input apex for both the prebuilt_apex and the deapexer. That is needed for a couple of reasons:
+// 1. To dedup the selection logic so it only runs in one module.
+// 2. To allow the deapexer to be wired up to a different source for the input apex, e.g. an
+// `apex_set`.
+//
+// prebuilt_apex
+// / | \
+// / | \
+// V | V
+// selector <--- deapexer <--- exported java lib
+//
func PrebuiltFactory() android.Module {
module := &Prebuilt{}
- module.AddProperties(&module.properties)
- android.InitPrebuiltModuleWithSrcSupplier(module, module.properties.prebuiltApexSelector, "src")
+ module.AddProperties(&module.properties, &module.deapexerProperties, &module.selectedApexProperties)
+ android.InitSingleSourcePrebuiltModule(module, &module.selectedApexProperties, "Selected_apex")
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
android.AddLoadHook(module, func(ctx android.LoadHookContext) {
- props := struct {
- Name *string
- }{
- Name: proptools.StringPtr(module.BaseModuleName() + ".deapexer"),
+ baseModuleName := module.BaseModuleName()
+
+ apexSelectorModuleName := apexSelectorModuleName(baseModuleName)
+ createApexSelectorModule(ctx, apexSelectorModuleName, &module.properties.ApexFileProperties)
+
+ apexFileSource := ":" + apexSelectorModuleName
+ if len(module.deapexerProperties.Exported_java_libs) != 0 {
+ createDeapexerModule(ctx, deapexerModuleName(baseModuleName), apexFileSource, &module.deapexerProperties)
}
- ctx.CreateModule(privateDeapexerFactory,
- &props,
- &module.properties.ApexFileProperties,
- &module.properties.DeapexerProperties,
- )
+
+ // Add a source reference to retrieve the selected apex from the selector module.
+ module.selectedApexProperties.Selected_apex = proptools.StringPtr(apexFileSource)
})
return module
}
+func createApexSelectorModule(ctx android.LoadHookContext, name string, apexFileProperties *ApexFileProperties) {
+ props := struct {
+ Name *string
+ }{
+ Name: proptools.StringPtr(name),
+ }
+
+ ctx.CreateModule(privateApexSelectorModuleFactory,
+ &props,
+ apexFileProperties,
+ )
+}
+
+func createDeapexerModule(ctx android.LoadHookContext, deapexerName string, apexFileSource string, deapexerProperties *DeapexerProperties) {
+ props := struct {
+ Name *string
+ Selected_apex *string
+ }{
+ Name: proptools.StringPtr(deapexerName),
+ Selected_apex: proptools.StringPtr(apexFileSource),
+ }
+ ctx.CreateModule(privateDeapexerFactory,
+ &props,
+ deapexerProperties,
+ )
+}
+
+func deapexerModuleName(baseModuleName string) string {
+ return baseModuleName + ".deapexer"
+}
+
+func apexSelectorModuleName(baseModuleName string) string {
+ return baseModuleName + ".apex.selector"
+}
+
func prebuiltApexExportedModuleName(ctx android.BottomUpMutatorContext, name string) string {
// The prebuilt_apex should be depending on prebuilt modules but as this runs after
// prebuilt_rename the prebuilt module may or may not be using the prebuilt_ prefixed named. So,
@@ -250,7 +423,7 @@
// the unprefixed name is the one to use. If the unprefixed one turns out to be a source module
// and not a renamed prebuilt module then that will be detected and reported as an error when
// processing the dependency in ApexInfoMutator().
- prebuiltName := "prebuilt_" + name
+ prebuiltName := android.PrebuiltNameFromSource(name)
if ctx.OtherModuleExists(prebuiltName) {
name = prebuiltName
}
@@ -282,100 +455,18 @@
)
func (p *Prebuilt) DepsMutator(ctx android.BottomUpMutatorContext) {
- // Add dependencies onto the java modules that represent the java libraries that are provided by
- // and exported from this prebuilt apex.
- for _, lib := range p.properties.Exported_java_libs {
- dep := prebuiltApexExportedModuleName(ctx, lib)
- ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(), exportedJavaLibTag, dep)
- }
+ p.deapexerDeps(ctx)
}
var _ ApexInfoMutator = (*Prebuilt)(nil)
-// ApexInfoMutator marks any modules for which this apex exports a file as requiring an apex
-// specific variant and checks that they are supported.
-//
-// The apexMutator will ensure that the ApexInfo objects passed to BuildForApex(ApexInfo) are
-// associated with the apex specific variant using the ApexInfoProvider for later retrieval.
-//
-// Unlike the source apex module type the prebuilt_apex module type cannot share compatible variants
-// across prebuilt_apex modules. That is because there is no way to determine whether two
-// prebuilt_apex modules that export files for the same module are compatible. e.g. they could have
-// been built from different source at different times or they could have been built with different
-// build options that affect the libraries.
-//
-// While it may be possible to provide sufficient information to determine whether two prebuilt_apex
-// modules were compatible it would be a lot of work and would not provide much benefit for a couple
-// of reasons:
-// * The number of prebuilt_apex modules that will be exporting files for the same module will be
-// low as the prebuilt_apex only exports files for the direct dependencies that require it and
-// very few modules are direct dependencies of multiple prebuilt_apex modules, e.g. there are a
-// few com.android.art* apex files that contain the same contents and could export files for the
-// same modules but only one of them needs to do so. Contrast that with source apex modules which
-// need apex specific variants for every module that contributes code to the apex, whether direct
-// or indirect.
-// * The build cost of a prebuilt_apex variant is generally low as at worst it will involve some
-// extra copying of files. Contrast that with source apex modules that has to build each variant
-// from source.
func (p *Prebuilt) ApexInfoMutator(mctx android.TopDownMutatorContext) {
-
- // Collect direct dependencies into contents.
- contents := make(map[string]android.ApexMembership)
-
- // Collect the list of dependencies.
- var dependencies []android.ApexModule
- mctx.VisitDirectDeps(func(m android.Module) {
- tag := mctx.OtherModuleDependencyTag(m)
- if tag == exportedJavaLibTag {
- depName := mctx.OtherModuleName(m)
-
- // It is an error if the other module is not a prebuilt.
- if _, ok := m.(android.PrebuiltInterface); !ok {
- mctx.PropertyErrorf("exported_java_libs", "%q is not a prebuilt module", depName)
- return
- }
-
- // It is an error if the other module is not an ApexModule.
- if _, ok := m.(android.ApexModule); !ok {
- mctx.PropertyErrorf("exported_java_libs", "%q is not usable within an apex", depName)
- return
- }
-
- // Strip off the prebuilt_ prefix if present before storing content to ensure consistent
- // behavior whether there is a corresponding source module present or not.
- depName = android.RemoveOptionalPrebuiltPrefix(depName)
-
- // Remember that this module was added as a direct dependency.
- contents[depName] = contents[depName].Add(true)
-
- // Add the module to the list of dependencies that need to have an APEX variant.
- dependencies = append(dependencies, m.(android.ApexModule))
- }
- })
-
- // Create contents for the prebuilt_apex and store it away for later use.
- apexContents := android.NewApexContents(contents)
- mctx.SetProvider(ApexBundleInfoProvider, ApexBundleInfo{
- Contents: apexContents,
- })
-
- // Create an ApexInfo for the prebuilt_apex.
- apexInfo := android.ApexInfo{
- ApexVariationName: mctx.ModuleName(),
- InApexes: []string{mctx.ModuleName()},
- ApexContents: []*android.ApexContents{apexContents},
- ForPrebuiltApex: true,
- }
-
- // Mark the dependencies of this module as requiring a variant for this module.
- for _, am := range dependencies {
- am.BuildForApex(apexInfo)
- }
+ p.apexInfoMutator(mctx)
}
func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
// TODO(jungjw): Check the key validity.
- p.inputApex = p.Prebuilt().SingleSourcePath(ctx)
+ p.inputApex = android.OptionalPathForModuleSrc(ctx, p.selectedApexProperties.Selected_apex).Path()
p.installDir = android.PathForModuleInstall(ctx, "apex")
p.installFilename = p.InstallFilename()
if !strings.HasSuffix(p.installFilename, imageApexSuffix) {
@@ -424,6 +515,49 @@
}}
}
+// prebuiltApexExtractorModule is a private module type that is only created by the prebuilt_apex
+// module. It extracts the correct apex to use and makes it available for use by apex_set.
+type prebuiltApexExtractorModule struct {
+ android.ModuleBase
+
+ properties ApexExtractorProperties
+
+ extractedApex android.WritablePath
+}
+
+func privateApexExtractorModuleFactory() android.Module {
+ module := &prebuiltApexExtractorModule{}
+ module.AddProperties(
+ &module.properties,
+ )
+ android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ return module
+}
+
+func (p *prebuiltApexExtractorModule) Srcs() android.Paths {
+ return android.Paths{p.extractedApex}
+}
+
+func (p *prebuiltApexExtractorModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ srcsSupplier := func(ctx android.BaseModuleContext, prebuilt android.Module) []string {
+ return p.properties.prebuiltSrcs(ctx)
+ }
+ apexSet := android.SingleSourcePathFromSupplier(ctx, srcsSupplier, "set")
+ p.extractedApex = android.PathForModuleOut(ctx, "extracted", apexSet.Base())
+ ctx.Build(pctx,
+ android.BuildParams{
+ Rule: extractMatchingApex,
+ Description: "Extract an apex from an apex set",
+ Inputs: android.Paths{apexSet},
+ Output: p.extractedApex,
+ Args: map[string]string{
+ "abis": strings.Join(java.SupportedAbis(ctx), ","),
+ "allow-prereleased": strconv.FormatBool(proptools.Bool(p.properties.Prerelease)),
+ "sdk-version": ctx.Config().PlatformSdkVersion().String(),
+ },
+ })
+}
+
type ApexSet struct {
android.ModuleBase
prebuiltCommon
@@ -442,7 +576,7 @@
postInstallCommands []string
}
-type ApexSetProperties struct {
+type ApexExtractorProperties struct {
// the .apks file path that contains prebuilt apex files to be extracted.
Set *string
@@ -458,6 +592,37 @@
}
}
+ // apexes in this set use prerelease SDK version
+ Prerelease *bool
+}
+
+func (e *ApexExtractorProperties) prebuiltSrcs(ctx android.BaseModuleContext) []string {
+ var srcs []string
+ if e.Set != nil {
+ srcs = append(srcs, *e.Set)
+ }
+
+ var sanitizers []string
+ if ctx.Host() {
+ sanitizers = ctx.Config().SanitizeHost()
+ } else {
+ sanitizers = ctx.Config().SanitizeDevice()
+ }
+
+ if android.InList("address", sanitizers) && e.Sanitized.Address.Set != nil {
+ srcs = append(srcs, *e.Sanitized.Address.Set)
+ } else if android.InList("hwaddress", sanitizers) && e.Sanitized.Hwaddress.Set != nil {
+ srcs = append(srcs, *e.Sanitized.Hwaddress.Set)
+ } else if e.Sanitized.None.Set != nil {
+ srcs = append(srcs, *e.Sanitized.None.Set)
+ }
+
+ return srcs
+}
+
+type ApexSetProperties struct {
+ ApexExtractorProperties
+
// whether the extracted apex file installable.
Installable *bool
@@ -471,33 +636,6 @@
// binaries would be installed by default (in PRODUCT_PACKAGES) the other binary will be removed
// from PRODUCT_PACKAGES.
Overrides []string
-
- // apexes in this set use prerelease SDK version
- Prerelease *bool
-}
-
-func (a *ApexSet) prebuiltSrcs(ctx android.BaseModuleContext) []string {
- var srcs []string
- if a.properties.Set != nil {
- srcs = append(srcs, *a.properties.Set)
- }
-
- var sanitizers []string
- if ctx.Host() {
- sanitizers = ctx.Config().SanitizeHost()
- } else {
- sanitizers = ctx.Config().SanitizeDevice()
- }
-
- if android.InList("address", sanitizers) && a.properties.Sanitized.Address.Set != nil {
- srcs = append(srcs, *a.properties.Sanitized.Address.Set)
- } else if android.InList("hwaddress", sanitizers) && a.properties.Sanitized.Hwaddress.Set != nil {
- srcs = append(srcs, *a.properties.Sanitized.Hwaddress.Set)
- } else if a.properties.Sanitized.None.Set != nil {
- srcs = append(srcs, *a.properties.Sanitized.None.Set)
- }
-
- return srcs
}
func (a *ApexSet) hasSanitizedSource(sanitizer string) bool {
@@ -530,15 +668,54 @@
// prebuilt_apex imports an `.apex` file into the build graph as if it was built with apex.
func apexSetFactory() android.Module {
module := &ApexSet{}
- module.AddProperties(&module.properties)
+ module.AddProperties(&module.properties, &module.selectedApexProperties, &module.deapexerProperties)
- srcsSupplier := func(ctx android.BaseModuleContext, _ android.Module) []string {
- return module.prebuiltSrcs(ctx)
+ android.InitSingleSourcePrebuiltModule(module, &module.selectedApexProperties, "Selected_apex")
+ android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
+
+ android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+ baseModuleName := module.BaseModuleName()
+
+ apexExtractorModuleName := apexExtractorModuleName(baseModuleName)
+ createApexExtractorModule(ctx, apexExtractorModuleName, &module.properties.ApexExtractorProperties)
+
+ apexFileSource := ":" + apexExtractorModuleName
+ if len(module.deapexerProperties.Exported_java_libs) != 0 {
+ createDeapexerModule(ctx, deapexerModuleName(baseModuleName), apexFileSource, &module.deapexerProperties)
+ }
+
+ // After passing the arch specific src properties to the creating the apex selector module
+ module.selectedApexProperties.Selected_apex = proptools.StringPtr(apexFileSource)
+ })
+
+ return module
+}
+
+func createApexExtractorModule(ctx android.LoadHookContext, name string, apexExtractorProperties *ApexExtractorProperties) {
+ props := struct {
+ Name *string
+ }{
+ Name: proptools.StringPtr(name),
}
- android.InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, "set")
- android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
- return module
+ ctx.CreateModule(privateApexExtractorModuleFactory,
+ &props,
+ apexExtractorProperties,
+ )
+}
+
+func apexExtractorModuleName(baseModuleName string) string {
+ return baseModuleName + ".apex.extractor"
+}
+
+func (a *ApexSet) DepsMutator(ctx android.BottomUpMutatorContext) {
+ a.deapexerDeps(ctx)
+}
+
+var _ ApexInfoMutator = (*ApexSet)(nil)
+
+func (a *ApexSet) ApexInfoMutator(mctx android.TopDownMutatorContext) {
+ a.apexInfoMutator(mctx)
}
func (a *ApexSet) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -547,20 +724,13 @@
ctx.ModuleErrorf("filename should end in %s for apex_set", imageApexSuffix)
}
- apexSet := a.prebuiltCommon.prebuilt.SingleSourcePath(ctx)
+ inputApex := android.OptionalPathForModuleSrc(ctx, a.selectedApexProperties.Selected_apex).Path()
a.outputApex = android.PathForModuleOut(ctx, a.installFilename)
- ctx.Build(pctx,
- android.BuildParams{
- Rule: extractMatchingApex,
- Description: "Extract an apex from an apex set",
- Inputs: android.Paths{apexSet},
- Output: a.outputApex,
- Args: map[string]string{
- "abis": strings.Join(java.SupportedAbis(ctx), ","),
- "allow-prereleased": strconv.FormatBool(proptools.Bool(a.properties.Prerelease)),
- "sdk-version": ctx.Config().PlatformSdkVersion().String(),
- },
- })
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Input: inputApex,
+ Output: a.outputApex,
+ })
if a.prebuiltCommon.checkForceDisable(ctx) {
a.HideFromMake()
diff --git a/apex/vndk_test.go b/apex/vndk_test.go
index 015283d..d580e5a 100644
--- a/apex/vndk_test.go
+++ b/apex/vndk_test.go
@@ -59,11 +59,11 @@
"lib/libc++.so",
"lib64/libvndksp.so",
"lib64/libc++.so",
- "etc/llndk.libraries.VER.txt",
- "etc/vndkcore.libraries.VER.txt",
- "etc/vndksp.libraries.VER.txt",
- "etc/vndkprivate.libraries.VER.txt",
- "etc/vndkproduct.libraries.VER.txt",
+ "etc/llndk.libraries.29.txt",
+ "etc/vndkcore.libraries.29.txt",
+ "etc/vndksp.libraries.29.txt",
+ "etc/vndkprivate.libraries.29.txt",
+ "etc/vndkproduct.libraries.29.txt",
})
}
@@ -111,7 +111,7 @@
// VNDK APEX doesn't create apex variant
files := getFiles(t, ctx, "com.android.vndk.current", "android_common_image")
- ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.VER_arm_armv7-a-neon_shared/libfoo.so")
+ ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.29_arm_armv7-a-neon_shared/libfoo.so")
})
t.Run("VNDK APEX gathers only vendor variants even if product variants are available", func(t *testing.T) {
@@ -123,7 +123,7 @@
)
files := getFiles(t, ctx, "com.android.vndk.current", "android_common_image")
- ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.VER_arm_armv7-a-neon_shared/libfoo.so")
+ ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.29_arm_armv7-a-neon_shared/libfoo.so")
})
t.Run("VNDK APEX supports coverage variants", func(t *testing.T) {
@@ -135,9 +135,9 @@
)
files := getFiles(t, ctx, "com.android.vndk.current", "android_common_image")
- ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.VER_arm_armv7-a-neon_shared/libfoo.so")
+ ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.29_arm_armv7-a-neon_shared/libfoo.so")
files = getFiles(t, ctx, "com.android.vndk.current", "android_common_cov_image")
- ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.VER_arm_armv7-a-neon_shared_cov/libfoo.so")
+ ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.29_arm_armv7-a-neon_shared_cov/libfoo.so")
})
}
diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go
index bd1ece1..8049108 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -1,89 +1,118 @@
package cquery
import (
+ "fmt"
"strings"
)
var (
- GetOutputFiles RequestType = &getOutputFilesRequestType{}
- GetOutputFilesAndCcObjectFiles RequestType = &getOutputFilesAndCcObjectFilesType{}
+ GetOutputFiles = &getOutputFilesRequestType{}
+ GetCcInfo = &getCcInfoType{}
)
-type GetOutputFilesAndCcObjectFiles_Result struct {
- OutputFiles []string
- CcObjectFiles []string
-}
-
-var RequestTypes []RequestType = []RequestType{
- GetOutputFiles,
- GetOutputFilesAndCcObjectFiles,
-}
-
-type RequestType interface {
- // Name returns a string name for this request type. Such request type names must be unique,
- // and must only consist of alphanumeric characters.
- Name() string
-
- // StarlarkFunctionBody returns a straark function body to process this request type.
- // The returned string is the body of a Starlark function which obtains
- // all request-relevant information about a target and returns a string containing
- // this information.
- // The function should have the following properties:
- // - `target` is the only parameter to this function (a configured target).
- // - The return value must be a string.
- // - The function body should not be indented outside of its own scope.
- StarlarkFunctionBody() string
-
- // ParseResult returns a value obtained by parsing the result of the request's Starlark function.
- // The given rawString must correspond to the string output which was created by evaluating the
- // Starlark given in StarlarkFunctionBody.
- // The type of this value depends on the request type; it is up to the caller to
- // cast to the correct type.
- ParseResult(rawString string) interface{}
+type CcInfo struct {
+ OutputFiles []string
+ CcObjectFiles []string
+ CcStaticLibraryFiles []string
}
type getOutputFilesRequestType struct{}
+// Name returns a string name for this request type. Such request type names must be unique,
+// and must only consist of alphanumeric characters.
func (g getOutputFilesRequestType) Name() string {
return "getOutputFiles"
}
+// StarlarkFunctionBody returns a starlark function body to process this request type.
+// The returned string is the body of a Starlark function which obtains
+// all request-relevant information about a target and returns a string containing
+// this information.
+// The function should have the following properties:
+// - `target` is the only parameter to this function (a configured target).
+// - The return value must be a string.
+// - The function body should not be indented outside of its own scope.
func (g getOutputFilesRequestType) StarlarkFunctionBody() string {
return "return ', '.join([f.path for f in target.files.to_list()])"
}
-func (g getOutputFilesRequestType) ParseResult(rawString string) interface{} {
- return strings.Split(rawString, ", ")
+// ParseResult returns a value obtained by parsing the result of the request's Starlark function.
+// The given rawString must correspond to the string output which was created by evaluating the
+// Starlark given in StarlarkFunctionBody.
+func (g getOutputFilesRequestType) ParseResult(rawString string) []string {
+ return splitOrEmpty(rawString, ", ")
}
-type getOutputFilesAndCcObjectFilesType struct{}
+type getCcInfoType struct{}
-func (g getOutputFilesAndCcObjectFilesType) Name() string {
- return "getOutputFilesAndCcObjectFiles"
+// Name returns a string name for this request type. Such request type names must be unique,
+// and must only consist of alphanumeric characters.
+func (g getCcInfoType) Name() string {
+ return "getCcInfo"
}
-func (g getOutputFilesAndCcObjectFilesType) StarlarkFunctionBody() string {
+// StarlarkFunctionBody returns a starlark function body to process this request type.
+// The returned string is the body of a Starlark function which obtains
+// all request-relevant information about a target and returns a string containing
+// this information.
+// The function should have the following properties:
+// - `target` is the only parameter to this function (a configured target).
+// - The return value must be a string.
+// - The function body should not be indented outside of its own scope.
+func (g getCcInfoType) StarlarkFunctionBody() string {
return `
outputFiles = [f.path for f in target.files.to_list()]
ccObjectFiles = []
+staticLibraries = []
linker_inputs = providers(target)["CcInfo"].linking_context.linker_inputs.to_list()
for linker_input in linker_inputs:
for library in linker_input.libraries:
for object in library.objects:
ccObjectFiles += [object.path]
-return ', '.join(outputFiles) + "|" + ', '.join(ccObjectFiles)`
+ if library.static_library:
+ staticLibraries.append(library.static_library.path)
+
+returns = [
+ outputFiles,
+ staticLibraries,
+ ccObjectFiles,
+]
+
+return "|".join([", ".join(r) for r in returns])`
}
-func (g getOutputFilesAndCcObjectFilesType) ParseResult(rawString string) interface{} {
+// ParseResult returns a value obtained by parsing the result of the request's Starlark function.
+// The given rawString must correspond to the string output which was created by evaluating the
+// Starlark given in StarlarkFunctionBody.
+func (g getCcInfoType) ParseResult(rawString string) (CcInfo, error) {
var outputFiles []string
var ccObjects []string
splitString := strings.Split(rawString, "|")
+ if expectedLen := 3; len(splitString) != expectedLen {
+ return CcInfo{}, fmt.Errorf("Expected %d items, got %q", expectedLen, splitString)
+ }
outputFilesString := splitString[0]
- ccObjectsString := splitString[1]
- outputFiles = strings.Split(outputFilesString, ", ")
- ccObjects = strings.Split(ccObjectsString, ", ")
- return GetOutputFilesAndCcObjectFiles_Result{outputFiles, ccObjects}
+ ccStaticLibrariesString := splitString[1]
+ ccObjectsString := splitString[2]
+ outputFiles = splitOrEmpty(outputFilesString, ", ")
+ ccStaticLibraries := splitOrEmpty(ccStaticLibrariesString, ", ")
+ ccObjects = splitOrEmpty(ccObjectsString, ", ")
+ return CcInfo{
+ OutputFiles: outputFiles,
+ CcObjectFiles: ccObjects,
+ CcStaticLibraryFiles: ccStaticLibraries,
+ }, nil
+}
+
+// splitOrEmpty is a modification of strings.Split() that returns an empty list
+// if the given string is empty.
+func splitOrEmpty(s string, sep string) []string {
+ if len(s) < 1 {
+ return []string{}
+ } else {
+ return strings.Split(s, sep)
+ }
}
diff --git a/bazel/cquery/request_type_test.go b/bazel/cquery/request_type_test.go
new file mode 100644
index 0000000..48edb90
--- /dev/null
+++ b/bazel/cquery/request_type_test.go
@@ -0,0 +1,95 @@
+package cquery
+
+import (
+ "fmt"
+ "reflect"
+ "testing"
+)
+
+func TestGetOutputFilesParseResults(t *testing.T) {
+ testCases := []struct {
+ description string
+ input string
+ expectedOutput []string
+ }{
+ {
+ description: "no result",
+ input: "",
+ expectedOutput: []string{},
+ },
+ {
+ description: "one result",
+ input: "test",
+ expectedOutput: []string{"test"},
+ },
+ {
+ description: "splits on comma with space",
+ input: "foo, bar",
+ expectedOutput: []string{"foo", "bar"},
+ },
+ }
+ for _, tc := range testCases {
+ actualOutput := GetOutputFiles.ParseResult(tc.input)
+ if !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
+ t.Errorf("%q: expected %#v != actual %#v", tc.description, tc.expectedOutput, actualOutput)
+ }
+ }
+}
+
+func TestGetCcInfoParseResults(t *testing.T) {
+ testCases := []struct {
+ description string
+ input string
+ expectedOutput CcInfo
+ expectedErrorMessage string
+ }{
+ {
+ description: "no result",
+ input: "||",
+ expectedOutput: CcInfo{
+ OutputFiles: []string{},
+ CcObjectFiles: []string{},
+ CcStaticLibraryFiles: []string{},
+ },
+ },
+ {
+ description: "only output",
+ input: "test||",
+ expectedOutput: CcInfo{
+ OutputFiles: []string{"test"},
+ CcObjectFiles: []string{},
+ CcStaticLibraryFiles: []string{},
+ },
+ },
+ {
+ description: "all items set",
+ input: "out1, out2|static_lib1, static_lib2|object1, object2",
+ expectedOutput: CcInfo{
+ OutputFiles: []string{"out1", "out2"},
+ CcObjectFiles: []string{"object1", "object2"},
+ CcStaticLibraryFiles: []string{"static_lib1", "static_lib2"},
+ },
+ },
+ {
+ description: "too few result splits",
+ input: "|",
+ expectedOutput: CcInfo{},
+ expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", 3, []string{"", ""}),
+ },
+ {
+ description: "too many result splits",
+ input: "|||",
+ expectedOutput: CcInfo{},
+ expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", 3, []string{"", "", "", ""}),
+ },
+ }
+ for _, tc := range testCases {
+ actualOutput, err := GetCcInfo.ParseResult(tc.input)
+ if (err == nil && tc.expectedErrorMessage != "") ||
+ (err != nil && err.Error() != tc.expectedErrorMessage) {
+ t.Errorf("%q: expected Error %s, got %s", tc.description, tc.expectedErrorMessage, err)
+ } else if err == nil && !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
+ t.Errorf("%q: expected %#v != actual %#v", tc.description, tc.expectedOutput, actualOutput)
+ }
+ }
+}
diff --git a/bazel/properties.go b/bazel/properties.go
index 1763f2d..4bb2391 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -16,6 +16,7 @@
import (
"fmt"
+ "path/filepath"
"regexp"
"sort"
)
@@ -47,6 +48,57 @@
Excludes []Label
}
+// GlobsInDir returns a list of glob expressions for a list of extensions
+// (optionally recursive) within a directory.
+func GlobsInDir(dir string, recursive bool, extensions []string) []string {
+ globs := []string{}
+
+ globInfix := ""
+ if dir == "." {
+ if recursive {
+ // e.g "**/*.h"
+ globInfix = "**/"
+ } // else e.g. "*.h"
+ for _, ext := range extensions {
+ globs = append(globs, globInfix+"*"+ext)
+ }
+ } else {
+ if recursive {
+ // e.g. "foo/bar/**/*.h"
+ dir += "/**"
+ } // else e.g. "foo/bar/*.h"
+ for _, ext := range extensions {
+ globs = append(globs, dir+"/*"+ext)
+ }
+ }
+ return globs
+}
+
+// LooseHdrsGlobs returns the list of non-recursive header globs for each parent directory of
+// each source file in this LabelList's Includes.
+func (ll *LabelList) LooseHdrsGlobs(exts []string) []string {
+ var globs []string
+ for _, parentDir := range ll.uniqueParentDirectories() {
+ globs = append(globs,
+ GlobsInDir(parentDir, false, exts)...)
+ }
+ return globs
+}
+
+// uniqueParentDirectories returns a list of the unique parent directories for
+// all files in ll.Includes.
+func (ll *LabelList) uniqueParentDirectories() []string {
+ dirMap := map[string]bool{}
+ for _, label := range ll.Includes {
+ dirMap[filepath.Dir(label.Label)] = true
+ }
+ dirs := []string{}
+ for dir := range dirMap {
+ dirs = append(dirs, dir)
+ }
+ return dirs
+}
+
// Append appends the fields of other labelList to the corresponding fields of ll.
func (ll *LabelList) Append(other LabelList) {
if len(ll.Includes) > 0 || len(other.Includes) > 0 {
@@ -79,21 +131,110 @@
return uniqueLabelList
}
+// Subtract needle from haystack
+func SubtractStrings(haystack []string, needle []string) []string {
+ // This is really a set
+ remainder := make(map[string]bool)
+
+ for _, s := range haystack {
+ remainder[s] = true
+ }
+ for _, s := range needle {
+ delete(remainder, s)
+ }
+
+ var strings []string
+ for s, _ := range remainder {
+ strings = append(strings, s)
+ }
+
+ sort.SliceStable(strings, func(i, j int) bool {
+ return strings[i] < strings[j]
+ })
+
+ return strings
+}
+
+// Subtract needle from haystack
+func SubtractBazelLabels(haystack []Label, needle []Label) []Label {
+ // This is really a set
+ remainder := make(map[Label]bool)
+
+ for _, label := range haystack {
+ remainder[label] = true
+ }
+ for _, label := range needle {
+ delete(remainder, label)
+ }
+
+ var labels []Label
+ for label, _ := range remainder {
+ labels = append(labels, label)
+ }
+
+ sort.SliceStable(labels, func(i, j int) bool {
+ return labels[i].Label < labels[j].Label
+ })
+
+ return labels
+}
+
+// Subtract needle from haystack
+func SubtractBazelLabelList(haystack LabelList, needle LabelList) LabelList {
+ var result LabelList
+ result.Includes = SubtractBazelLabels(haystack.Includes, needle.Includes)
+ // NOTE: Excludes are intentionally not subtracted
+ result.Excludes = haystack.Excludes
+ return result
+}
+
const (
- ARCH_X86 = "x86"
- ARCH_X86_64 = "x86_64"
+ // ArchType names in arch.go
ARCH_ARM = "arm"
ARCH_ARM64 = "arm64"
+ ARCH_X86 = "x86"
+ ARCH_X86_64 = "x86_64"
+
+ // OsType names in arch.go
+ OS_ANDROID = "android"
+ OS_DARWIN = "darwin"
+ OS_FUCHSIA = "fuchsia"
+ OS_LINUX = "linux_glibc"
+ OS_LINUX_BIONIC = "linux_bionic"
+ OS_WINDOWS = "windows"
)
var (
- // This is the list of architectures with a Bazel config_setting and
- // constraint value equivalent. is actually android.ArchTypeList, but the
- // android package depends on the bazel package, so a cyclic dependency
- // prevents using that here.
- selectableArchs = []string{ARCH_X86, ARCH_X86_64, ARCH_ARM, ARCH_ARM64}
+ // These are the list of OSes and architectures with a Bazel config_setting
+ // and constraint value equivalent. These exist in arch.go, but the android
+ // package depends on the bazel package, so a cyclic dependency prevents
+ // using those variables here.
+
+ // A map of architectures to the Bazel label of the constraint_value
+ // for the @platforms//cpu:cpu constraint_setting
+ PlatformArchMap = map[string]string{
+ ARCH_ARM: "//build/bazel/platforms/arch:arm",
+ ARCH_ARM64: "//build/bazel/platforms/arch:arm64",
+ ARCH_X86: "//build/bazel/platforms/arch:x86",
+ ARCH_X86_64: "//build/bazel/platforms/arch:x86_64",
+ }
+
+ // A map of target operating systems to the Bazel label of the
+ // constraint_value for the @platforms//os:os constraint_setting
+ PlatformOsMap = map[string]string{
+ OS_ANDROID: "//build/bazel/platforms/os:android",
+ OS_DARWIN: "//build/bazel/platforms/os:darwin",
+ OS_FUCHSIA: "//build/bazel/platforms/os:fuchsia",
+ OS_LINUX: "//build/bazel/platforms/os:linux",
+ OS_LINUX_BIONIC: "//build/bazel/platforms/os:linux_bionic",
+ OS_WINDOWS: "//build/bazel/platforms/os:windows",
+ }
)
+type Attribute interface {
+ HasConfigurableValues() bool
+}
+
// Arch-specific label_list typed Bazel attribute values. This should correspond
// to the types of architectures supported for compilation in arch.go.
type labelListArchValues struct {
@@ -101,8 +242,16 @@
X86_64 LabelList
Arm LabelList
Arm64 LabelList
- // TODO(b/181299724): this is currently missing the "common" arch, which
- // doesn't have an equivalent platform() definition yet.
+ Common LabelList
+}
+
+type labelListOsValues struct {
+ Android LabelList
+ Darwin LabelList
+ Fuchsia LabelList
+ Linux LabelList
+ LinuxBionic LabelList
+ Windows LabelList
}
// LabelListAttribute is used to represent a list of Bazel labels as an
@@ -115,6 +264,11 @@
// are generated in a select statement and appended to the non-arch specific
// label list Value.
ArchValues labelListArchValues
+
+ // 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
}
// MakeLabelListAttribute initializes a LabelListAttribute with the non-arch specific value.
@@ -122,47 +276,97 @@
return LabelListAttribute{Value: UniqueBazelLabelList(value)}
}
+// Append appends all values, including os and arch specific ones, from another
+// LabelListAttribute to this LabelListAttribute.
+func (attrs *LabelListAttribute) Append(other LabelListAttribute) {
+ for arch := range PlatformArchMap {
+ this := attrs.GetValueForArch(arch)
+ that := other.GetValueForArch(arch)
+ this.Append(that)
+ attrs.SetValueForArch(arch, this)
+ }
+
+ for os := range PlatformOsMap {
+ this := attrs.GetValueForOS(os)
+ that := other.GetValueForOS(os)
+ this.Append(that)
+ attrs.SetValueForOS(os, this)
+ }
+
+ attrs.Value.Append(other.Value)
+}
+
// HasArchSpecificValues returns true if the attribute contains
// architecture-specific label_list values.
-func (attrs *LabelListAttribute) HasArchSpecificValues() bool {
- for _, arch := range selectableArchs {
- if len(attrs.GetValueForArch(arch).Includes) > 0 || len(attrs.GetValueForArch(arch).Excludes) > 0 {
+func (attrs LabelListAttribute) HasConfigurableValues() bool {
+ for arch := range PlatformArchMap {
+ if len(attrs.GetValueForArch(arch).Includes) > 0 {
+ return true
+ }
+ }
+
+ for os := range PlatformOsMap {
+ if len(attrs.GetValueForOS(os).Includes) > 0 {
return true
}
}
return false
}
+func (attrs *LabelListAttribute) archValuePtrs() map[string]*LabelList {
+ return map[string]*LabelList{
+ ARCH_X86: &attrs.ArchValues.X86,
+ ARCH_X86_64: &attrs.ArchValues.X86_64,
+ ARCH_ARM: &attrs.ArchValues.Arm,
+ ARCH_ARM64: &attrs.ArchValues.Arm64,
+ }
+}
+
// GetValueForArch returns the label_list attribute value for an architecture.
func (attrs *LabelListAttribute) GetValueForArch(arch string) LabelList {
- switch arch {
- case ARCH_X86:
- return attrs.ArchValues.X86
- case ARCH_X86_64:
- return attrs.ArchValues.X86_64
- case ARCH_ARM:
- return attrs.ArchValues.Arm
- case ARCH_ARM64:
- return attrs.ArchValues.Arm64
- default:
+ var v *LabelList
+ if v = attrs.archValuePtrs()[arch]; v == nil {
panic(fmt.Errorf("Unknown arch: %s", arch))
}
+ return *v
}
// SetValueForArch sets the label_list attribute value for an architecture.
func (attrs *LabelListAttribute) SetValueForArch(arch string, value LabelList) {
- switch arch {
- case "x86":
- attrs.ArchValues.X86 = value
- case "x86_64":
- attrs.ArchValues.X86_64 = value
- case "arm":
- attrs.ArchValues.Arm = value
- case "arm64":
- attrs.ArchValues.Arm64 = value
- default:
+ var v *LabelList
+ if v = attrs.archValuePtrs()[arch]; v == nil {
panic(fmt.Errorf("Unknown arch: %s", arch))
}
+ *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,
+ }
+}
+
+// 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 {
+ 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 {
+ panic(fmt.Errorf("Unknown os: %s", os))
+ }
+ *v = value
}
// StringListAttribute corresponds to the string_list Bazel attribute type with
@@ -171,8 +375,21 @@
// The base value of the string list attribute.
Value []string
- // Optional additive set of list values to the base value.
+ // The arch-specific attribute string list values. Optional. If used, these
+ // are generated in a select statement and appended to the non-arch specific
+ // label list Value.
ArchValues stringListArchValues
+
+ // 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
+}
+
+// MakeStringListAttribute initializes a StringListAttribute with the non-arch specific value.
+func MakeStringListAttribute(value []string) StringListAttribute {
+ // NOTE: These strings are not necessarily unique or sorted.
+ return StringListAttribute{Value: value}
}
// Arch-specific string_list typed Bazel attribute values. This should correspond
@@ -182,51 +399,89 @@
X86_64 []string
Arm []string
Arm64 []string
- // TODO(b/181299724): this is currently missing the "common" arch, which
- // doesn't have an equivalent platform() definition yet.
+ Common []string
}
-// HasArchSpecificValues returns true if the attribute contains
+type stringListOsValues struct {
+ Android []string
+ Darwin []string
+ Fuchsia []string
+ Linux []string
+ LinuxBionic []string
+ Windows []string
+}
+
+// HasConfigurableValues returns true if the attribute contains
// architecture-specific string_list values.
-func (attrs *StringListAttribute) HasArchSpecificValues() bool {
- for _, arch := range selectableArchs {
+func (attrs StringListAttribute) HasConfigurableValues() bool {
+ for arch := range PlatformArchMap {
if len(attrs.GetValueForArch(arch)) > 0 {
return true
}
}
+
+ for os := range PlatformOsMap {
+ if len(attrs.GetValueForOS(os)) > 0 {
+ return true
+ }
+ }
return false
}
+func (attrs *StringListAttribute) archValuePtrs() map[string]*[]string {
+ return map[string]*[]string{
+ ARCH_X86: &attrs.ArchValues.X86,
+ ARCH_X86_64: &attrs.ArchValues.X86_64,
+ ARCH_ARM: &attrs.ArchValues.Arm,
+ ARCH_ARM64: &attrs.ArchValues.Arm64,
+ }
+}
+
// GetValueForArch returns the string_list attribute value for an architecture.
func (attrs *StringListAttribute) GetValueForArch(arch string) []string {
- switch arch {
- case ARCH_X86:
- return attrs.ArchValues.X86
- case ARCH_X86_64:
- return attrs.ArchValues.X86_64
- case ARCH_ARM:
- return attrs.ArchValues.Arm
- case ARCH_ARM64:
- return attrs.ArchValues.Arm64
- default:
+ var v *[]string
+ if v = attrs.archValuePtrs()[arch]; v == nil {
panic(fmt.Errorf("Unknown arch: %s", arch))
}
+ return *v
}
// SetValueForArch sets the string_list attribute value for an architecture.
func (attrs *StringListAttribute) SetValueForArch(arch string, value []string) {
- switch arch {
- case ARCH_X86:
- attrs.ArchValues.X86 = value
- case ARCH_X86_64:
- attrs.ArchValues.X86_64 = value
- case ARCH_ARM:
- attrs.ArchValues.Arm = value
- case ARCH_ARM64:
- attrs.ArchValues.Arm64 = value
- default:
+ var v *[]string
+ if v = attrs.archValuePtrs()[arch]; v == nil {
panic(fmt.Errorf("Unknown arch: %s", arch))
}
+ *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,
+ }
+}
+
+// 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 {
+ 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 {
+ panic(fmt.Errorf("Unknown os: %s", os))
+ }
+ *v = value
}
// TryVariableSubstitution, replace string substitution formatting within each string in slice with
diff --git a/bazel/properties_test.go b/bazel/properties_test.go
index 0fcb904..56840ef 100644
--- a/bazel/properties_test.go
+++ b/bazel/properties_test.go
@@ -46,6 +46,82 @@
}
}
+func TestSubtractStrings(t *testing.T) {
+ testCases := []struct {
+ haystack []string
+ needle []string
+ expectedResult []string
+ }{
+ {
+ haystack: []string{
+ "a",
+ "b",
+ "c",
+ },
+ needle: []string{
+ "a",
+ },
+ expectedResult: []string{
+ "b", "c",
+ },
+ },
+ }
+ for _, tc := range testCases {
+ actualResult := SubtractStrings(tc.haystack, tc.needle)
+ if !reflect.DeepEqual(tc.expectedResult, actualResult) {
+ t.Fatalf("Expected %v, got %v", tc.expectedResult, actualResult)
+ }
+ }
+}
+
+func TestSubtractBazelLabelList(t *testing.T) {
+ testCases := []struct {
+ haystack LabelList
+ needle LabelList
+ expectedResult LabelList
+ }{
+ {
+ haystack: LabelList{
+ Includes: []Label{
+ {Label: "a"},
+ {Label: "b"},
+ {Label: "c"},
+ },
+ Excludes: []Label{
+ {Label: "x"},
+ {Label: "y"},
+ {Label: "z"},
+ },
+ },
+ needle: LabelList{
+ Includes: []Label{
+ {Label: "a"},
+ },
+ Excludes: []Label{
+ {Label: "z"},
+ },
+ },
+ // NOTE: Excludes are intentionally not subtracted
+ expectedResult: LabelList{
+ Includes: []Label{
+ {Label: "b"},
+ {Label: "c"},
+ },
+ Excludes: []Label{
+ {Label: "x"},
+ {Label: "y"},
+ {Label: "z"},
+ },
+ },
+ },
+ }
+ for _, tc := range testCases {
+ actualResult := SubtractBazelLabelList(tc.haystack, tc.needle)
+ if !reflect.DeepEqual(tc.expectedResult, actualResult) {
+ t.Fatalf("Expected %v, got %v", tc.expectedResult, actualResult)
+ }
+ }
+}
func TestUniqueBazelLabelList(t *testing.T) {
testCases := []struct {
originalLabelList LabelList
diff --git a/bloaty/Android.bp b/bloaty/Android.bp
index 96cc1a5..7e722a7 100644
--- a/bloaty/Android.bp
+++ b/bloaty/Android.bp
@@ -11,6 +11,7 @@
],
srcs: [
"bloaty.go",
+ "testing.go",
],
pluginFor: ["soong_build"],
}
diff --git a/bloaty/bloaty.go b/bloaty/bloaty.go
index 653c489..50f241f 100644
--- a/bloaty/bloaty.go
+++ b/bloaty/bloaty.go
@@ -23,7 +23,7 @@
)
const bloatyDescriptorExt = ".bloaty.csv"
-const protoFilename = "binary_sizes.pb"
+const protoFilename = "binary_sizes.pb.gz"
var (
fileSizeMeasurerKey blueprint.ProviderKey
@@ -52,12 +52,28 @@
pctx.SourcePathVariable("bloaty", "prebuilts/build-tools/${hostPrebuiltTag}/bin/bloaty")
pctx.HostBinToolVariable("bloatyMerger", "bloaty_merger")
android.RegisterSingletonType("file_metrics", fileSizesSingleton)
- fileSizeMeasurerKey = blueprint.NewProvider(android.ModuleOutPath{})
+ fileSizeMeasurerKey = blueprint.NewProvider(measuredFiles{})
}
-// MeasureSizeForPath should be called by binary producers (e.g. in builder.go).
-func MeasureSizeForPath(ctx android.ModuleContext, filePath android.WritablePath) {
- ctx.SetProvider(fileSizeMeasurerKey, filePath)
+// measuredFiles contains the paths of the files measured by a module.
+type measuredFiles struct {
+ paths []android.WritablePath
+}
+
+// MeasureSizeForPaths should be called by binary producers to measure the
+// sizes of artifacts. It must only be called once per module; it will panic
+// otherwise.
+func MeasureSizeForPaths(ctx android.ModuleContext, paths ...android.OptionalPath) {
+ mf := measuredFiles{}
+ for _, p := range paths {
+ if !p.Valid() {
+ continue
+ }
+ if p, ok := p.Path().(android.WritablePath); ok {
+ mf.paths = append(mf.paths, p)
+ }
+ }
+ ctx.SetProvider(fileSizeMeasurerKey, mf)
}
type sizesSingleton struct{}
@@ -68,21 +84,22 @@
func (singleton *sizesSingleton) GenerateBuildActions(ctx android.SingletonContext) {
var deps android.Paths
- // Visit all modules. If the size provider give us a binary path to measure,
- // create the rule to measure it.
ctx.VisitAllModules(func(m android.Module) {
if !ctx.ModuleHasProvider(m, fileSizeMeasurerKey) {
return
}
- filePath := ctx.ModuleProvider(m, fileSizeMeasurerKey).(android.ModuleOutPath)
- sizeFile := filePath.InSameDir(ctx, filePath.Base()+bloatyDescriptorExt)
- ctx.Build(pctx, android.BuildParams{
- Rule: bloaty,
- Description: "bloaty " + filePath.Rel(),
- Input: filePath,
- Output: sizeFile,
- })
- deps = append(deps, sizeFile)
+ filePaths := ctx.ModuleProvider(m, fileSizeMeasurerKey).(measuredFiles)
+ for _, path := range filePaths.paths {
+ filePath := path.(android.ModuleOutPath)
+ sizeFile := filePath.InSameDir(ctx, filePath.Base()+bloatyDescriptorExt)
+ ctx.Build(pctx, android.BuildParams{
+ Rule: bloaty,
+ Description: "bloaty " + filePath.Rel(),
+ Input: filePath,
+ Output: sizeFile,
+ })
+ deps = append(deps, sizeFile)
+ }
})
ctx.Build(pctx, android.BuildParams{
diff --git a/bloaty/bloaty_merger.py b/bloaty/bloaty_merger.py
index c873fb8..1034462 100644
--- a/bloaty/bloaty_merger.py
+++ b/bloaty/bloaty_merger.py
@@ -16,12 +16,13 @@
Merges a list of .csv files from Bloaty into a protobuf. It takes the list as
a first argument and the output as second. For instance:
- $ bloaty_merger binary_sizes.lst binary_sizes.pb
+ $ bloaty_merger binary_sizes.lst binary_sizes.pb.gz
"""
import argparse
import csv
+import gzip
import ninja_rsp
@@ -57,7 +58,8 @@
Args:
input_list: The path to the file which contains the list of CSV files. Each
filepath is separated by a space.
- output_proto: The path for the output protobuf.
+ output_proto: The path for the output protobuf. It will be compressed using
+ gzip.
"""
metrics = file_sections_pb2.FileSizeMetrics()
reader = ninja_rsp.NinjaRspFileReader(input_list)
@@ -65,7 +67,7 @@
file_proto = parse_csv(csv_path)
if file_proto:
metrics.files.append(file_proto)
- with open(output_proto, "wb") as output:
+ with gzip.open(output_proto, "wb") as output:
output.write(metrics.SerializeToString())
def main():
diff --git a/bloaty/bloaty_merger_test.py b/bloaty/bloaty_merger_test.py
index 0e3641d..9de049a 100644
--- a/bloaty/bloaty_merger_test.py
+++ b/bloaty/bloaty_merger_test.py
@@ -11,6 +11,7 @@
# 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 gzip
import unittest
from pyfakefs import fake_filesystem_unittest
@@ -53,10 +54,10 @@
self.fs.create_file("file1.bloaty.csv", contents=file1_content)
self.fs.create_file("file2.bloaty.csv", contents=file2_content)
- bloaty_merger.create_file_size_metrics("files.lst", "output.pb")
+ bloaty_merger.create_file_size_metrics("files.lst", "output.pb.gz")
metrics = file_sections_pb2.FileSizeMetrics()
- with open("output.pb", "rb") as output:
+ with gzip.open("output.pb.gz", "rb") as output:
metrics.ParseFromString(output.read())
diff --git a/bloaty/testing.go b/bloaty/testing.go
new file mode 100644
index 0000000..5f5ec84
--- /dev/null
+++ b/bloaty/testing.go
@@ -0,0 +1,25 @@
+// 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 bloaty
+
+import (
+ "android/soong/android"
+)
+
+// Preparer that will define the default bloaty singleton.
+var PrepareForTestWithBloatyDefaultModules = android.GroupFixturePreparers(
+ android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
+ ctx.RegisterSingletonType("file_metrics", fileSizesSingleton)
+ }))
diff --git a/bootstrap_test.sh b/bootstrap_test.sh
deleted file mode 100755
index 6c5338a..0000000
--- a/bootstrap_test.sh
+++ /dev/null
@@ -1,415 +0,0 @@
-#!/bin/bash -eu
-
-# This test exercises the bootstrapping process of the build system
-# in a source tree that only contains enough files for Bazel and Soong to work.
-
-HARDWIRED_MOCK_TOP=
-# Uncomment this to be able to view the source tree after a test is run
-# HARDWIRED_MOCK_TOP=/tmp/td
-
-REAL_TOP="$(readlink -f "$(dirname "$0")"/../..)"
-
-function fail {
- echo ERROR: $1
- exit 1
-}
-
-function copy_directory() {
- local dir="$1"
- local parent="$(dirname "$dir")"
-
- mkdir -p "$MOCK_TOP/$parent"
- cp -R "$REAL_TOP/$dir" "$MOCK_TOP/$parent"
-}
-
-function symlink_file() {
- local file="$1"
-
- mkdir -p "$MOCK_TOP/$(dirname "$file")"
- ln -s "$REAL_TOP/$file" "$MOCK_TOP/$file"
-}
-
-function symlink_directory() {
- local dir="$1"
-
- mkdir -p "$MOCK_TOP/$dir"
- # We need to symlink the contents of the directory individually instead of
- # using one symlink for the whole directory because finder.go doesn't follow
- # symlinks when looking for Android.bp files
- for i in $(ls "$REAL_TOP/$dir"); do
- local target="$MOCK_TOP/$dir/$i"
- local source="$REAL_TOP/$dir/$i"
-
- if [[ -e "$target" ]]; then
- if [[ ! -d "$source" || ! -d "$target" ]]; then
- fail "Trying to symlink $dir twice"
- fi
- else
- ln -s "$REAL_TOP/$dir/$i" "$MOCK_TOP/$dir/$i";
- fi
- done
-}
-
-function setup_bazel() {
- copy_directory build/bazel
-
- symlink_directory prebuilts/bazel
- symlink_directory prebuilts/jdk
-
- symlink_file WORKSPACE
- symlink_file tools/bazel
-}
-
-function setup() {
- if [[ ! -z "$HARDWIRED_MOCK_TOP" ]]; then
- MOCK_TOP="$HARDWIRED_MOCK_TOP"
- rm -fr "$MOCK_TOP"
- mkdir -p "$MOCK_TOP"
- else
- MOCK_TOP=$(mktemp -t -d st.XXXXX)
- trap 'echo cd / && echo rm -fr "$MOCK_TOP"' EXIT
- fi
-
- echo "Test case: ${FUNCNAME[1]}, mock top path: $MOCK_TOP"
- cd "$MOCK_TOP"
-
- copy_directory build/blueprint
- copy_directory build/soong
-
- symlink_directory prebuilts/go
- symlink_directory prebuilts/build-tools
- symlink_directory external/golang-protobuf
-
- touch "$MOCK_TOP/Android.bp"
-
- export ALLOW_MISSING_DEPENDENCIES=true
-
- mkdir -p out/soong
-}
-
-function run_soong() {
- build/soong/soong_ui.bash --make-mode --skip-ninja --skip-make --skip-soong-tests
-}
-
-function test_smoke {
- setup
- run_soong
-}
-
-function test_bazel_smoke {
- setup
- setup_bazel
-
- tools/bazel info
-
-}
-function test_null_build() {
- setup
- run_soong
- local bootstrap_mtime1=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
- local output_mtime1=$(stat -c "%y" out/soong/build.ninja)
- run_soong
- local bootstrap_mtime2=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
- local output_mtime2=$(stat -c "%y" out/soong/build.ninja)
-
- if [[ "$bootstrap_mtime1" == "$bootstrap_mtime2" ]]; then
- # Bootstrapping is always done. It doesn't take a measurable amount of time.
- fail "Bootstrap Ninja file did not change on null build"
- fi
-
- if [[ "$output_mtime1" != "$output_mtime2" ]]; then
- fail "Output Ninja file changed on null build"
- fi
-}
-
-function test_soong_build_rebuilt_if_blueprint_changes() {
- setup
- run_soong
- local mtime1=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
-
- sed -i 's/pluginGenSrcCmd/pluginGenSrcCmd2/g' build/blueprint/bootstrap/bootstrap.go
-
- run_soong
- local mtime2=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
-
- if [[ "$mtime1" == "$mtime2" ]]; then
- fail "Bootstrap Ninja file did not change"
- fi
-}
-
-function test_change_android_bp() {
- setup
- mkdir -p a
- cat > a/Android.bp <<'EOF'
-python_binary_host {
- name: "my_little_binary_host",
- srcs: ["my_little_binary_host.py"]
-}
-EOF
- touch a/my_little_binary_host.py
- run_soong
-
- grep -q "^# Module:.*my_little_binary_host" out/soong/build.ninja || fail "module not found"
-
- cat > a/Android.bp <<'EOF'
-python_binary_host {
- name: "my_great_binary_host",
- srcs: ["my_great_binary_host.py"]
-}
-EOF
- touch a/my_great_binary_host.py
- run_soong
-
- grep -q "^# Module:.*my_little_binary_host" out/soong/build.ninja && fail "old module found"
- grep -q "^# Module:.*my_great_binary_host" out/soong/build.ninja || fail "new module not found"
-}
-
-
-function test_add_android_bp() {
- setup
- run_soong
- local mtime1=$(stat -c "%y" out/soong/build.ninja)
-
- mkdir -p a
- cat > a/Android.bp <<'EOF'
-python_binary_host {
- name: "my_little_binary_host",
- srcs: ["my_little_binary_host.py"]
-}
-EOF
- touch a/my_little_binary_host.py
- run_soong
-
- local mtime2=$(stat -c "%y" out/soong/build.ninja)
- if [[ "$mtime1" == "$mtime2" ]]; then
- fail "Output Ninja file did not change"
- fi
-
- grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja || fail "New module not in output"
-
- run_soong
-}
-
-function test_delete_android_bp() {
- setup
- mkdir -p a
- cat > a/Android.bp <<'EOF'
-python_binary_host {
- name: "my_little_binary_host",
- srcs: ["my_little_binary_host.py"]
-}
-EOF
- touch a/my_little_binary_host.py
- run_soong
-
- grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja || fail "Module not in output"
-
- rm a/Android.bp
- run_soong
-
- grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja && fail "Old module in output"
-}
-
-function test_add_file_to_glob() {
- setup
-
- mkdir -p a
- cat > a/Android.bp <<'EOF'
-python_binary_host {
- name: "my_little_binary_host",
- srcs: ["*.py"],
-}
-EOF
- touch a/my_little_binary_host.py
- run_soong
- local mtime1=$(stat -c "%y" out/soong/build.ninja)
-
- touch a/my_little_library.py
- run_soong
-
- local mtime2=$(stat -c "%y" out/soong/build.ninja)
- if [[ "$mtime1" == "$mtime2" ]]; then
- fail "Output Ninja file did not change"
- fi
-
- grep -q my_little_library.py out/soong/build.ninja || fail "new file is not in output"
-}
-
-function test_soong_build_rerun_iff_environment_changes() {
- setup
-
- mkdir -p cherry
- cat > cherry/Android.bp <<'EOF'
-bootstrap_go_package {
- name: "cherry",
- pkgPath: "android/soong/cherry",
- deps: [
- "blueprint",
- "soong",
- "soong-android",
- ],
- srcs: [
- "cherry.go",
- ],
- pluginFor: ["soong_build"],
-}
-EOF
-
- cat > cherry/cherry.go <<'EOF'
-package cherry
-
-import (
- "android/soong/android"
- "github.com/google/blueprint"
-)
-
-var (
- pctx = android.NewPackageContext("cherry")
-)
-
-func init() {
- android.RegisterSingletonType("cherry", CherrySingleton)
-}
-
-func CherrySingleton() android.Singleton {
- return &cherrySingleton{}
-}
-
-type cherrySingleton struct{}
-
-func (p *cherrySingleton) GenerateBuildActions(ctx android.SingletonContext) {
- cherryRule := ctx.Rule(pctx, "cherry",
- blueprint.RuleParams{
- Command: "echo CHERRY IS " + ctx.Config().Getenv("CHERRY") + " > ${out}",
- CommandDeps: []string{},
- Description: "Cherry",
- })
-
- outputFile := android.PathForOutput(ctx, "cherry", "cherry.txt")
- var deps android.Paths
-
- ctx.Build(pctx, android.BuildParams{
- Rule: cherryRule,
- Output: outputFile,
- Inputs: deps,
- })
-}
-EOF
-
- export CHERRY=TASTY
- run_soong
- grep -q "CHERRY IS TASTY" out/soong/build.ninja \
- || fail "first value of environment variable is not used"
-
- export CHERRY=RED
- run_soong
- grep -q "CHERRY IS RED" out/soong/build.ninja \
- || fail "second value of environment variable not used"
- local mtime1=$(stat -c "%y" out/soong/build.ninja)
-
- run_soong
- local mtime2=$(stat -c "%y" out/soong/build.ninja)
- if [[ "$mtime1" != "$mtime2" ]]; then
- fail "Output Ninja file changed when environment variable did not"
- fi
-
-}
-
-function test_add_file_to_soong_build() {
- setup
- run_soong
- local mtime1=$(stat -c "%y" out/soong/build.ninja)
-
- mkdir -p a
- cat > a/Android.bp <<'EOF'
-bootstrap_go_package {
- name: "picard-soong-rules",
- pkgPath: "android/soong/picard",
- deps: [
- "blueprint",
- "soong",
- "soong-android",
- ],
- srcs: [
- "picard.go",
- ],
- pluginFor: ["soong_build"],
-}
-EOF
-
- cat > a/picard.go <<'EOF'
-package picard
-
-import (
- "android/soong/android"
- "github.com/google/blueprint"
-)
-
-var (
- pctx = android.NewPackageContext("picard")
-)
-
-func init() {
- android.RegisterSingletonType("picard", PicardSingleton)
-}
-
-func PicardSingleton() android.Singleton {
- return &picardSingleton{}
-}
-
-type picardSingleton struct{}
-
-func (p *picardSingleton) GenerateBuildActions(ctx android.SingletonContext) {
- picardRule := ctx.Rule(pctx, "picard",
- blueprint.RuleParams{
- Command: "echo Make it so. > ${out}",
- CommandDeps: []string{},
- Description: "Something quotable",
- })
-
- outputFile := android.PathForOutput(ctx, "picard", "picard.txt")
- var deps android.Paths
-
- ctx.Build(pctx, android.BuildParams{
- Rule: picardRule,
- Output: outputFile,
- Inputs: deps,
- })
-}
-
-EOF
-
- run_soong
- local mtime2=$(stat -c "%y" out/soong/build.ninja)
- if [[ "$mtime1" == "$mtime2" ]]; then
- fail "Output Ninja file did not change"
- fi
-
- grep -q "Make it so" out/soong/build.ninja || fail "New action not present"
-}
-
-function test_null_build_after_docs {
- setup
- run_soong
- local mtime1=$(stat -c "%y" out/soong/build.ninja)
-
- prebuilts/build-tools/linux-x86/bin/ninja -f out/soong/build.ninja soong_docs
- run_soong
- local mtime2=$(stat -c "%y" out/soong/build.ninja)
-
- if [[ "$mtime1" != "$mtime2" ]]; then
- fail "Output Ninja file changed on null build"
- fi
-}
-
-test_bazel_smoke
-test_smoke
-test_null_build
-test_null_build_after_docs
-test_soong_build_rebuilt_if_blueprint_changes
-test_add_file_to_glob
-test_add_android_bp
-test_change_android_bp
-test_delete_android_bp
-test_add_file_to_soong_build
-test_soong_build_rerun_iff_environment_changes
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index cc616f2..d2a8729 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -26,6 +26,7 @@
testSrcs: [
"build_conversion_test.go",
"bzl_conversion_test.go",
+ "cc_library_conversion_test.go",
"cc_library_headers_conversion_test.go",
"cc_library_static_conversion_test.go",
"cc_object_conversion_test.go",
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index e93b3dc..b7a2810 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -374,16 +374,9 @@
// value>)" to set the default value of unset attributes. In the cases
// where the bp2build converter didn't set the default value within the
// mutator when creating the BazelTargetModule, this would be a zero
- // value. For those cases, we return a non-surprising default value so
- // generated BUILD files are syntactically correct.
- switch propertyValue.Kind() {
- case reflect.Slice:
- return "[]", nil
- case reflect.Map:
- return "{}", nil
- default:
- return "", nil
- }
+ // value. For those cases, we return an empty string so we don't
+ // unnecessarily generate empty values.
+ return "", nil
}
var ret string
@@ -397,82 +390,45 @@
case reflect.Ptr:
return prettyPrint(propertyValue.Elem(), indent)
case reflect.Slice:
- ret = "[\n"
- for i := 0; i < propertyValue.Len(); i++ {
- indexedValue, err := prettyPrint(propertyValue.Index(i), indent+1)
+ if propertyValue.Len() == 0 {
+ return "", nil
+ }
+
+ if propertyValue.Len() == 1 {
+ // Single-line list for list with only 1 element
+ ret += "["
+ indexedValue, err := prettyPrint(propertyValue.Index(0), indent)
if err != nil {
return "", err
}
+ ret += indexedValue
+ ret += "]"
+ } else {
+ // otherwise, use a multiline list.
+ ret += "[\n"
+ for i := 0; i < propertyValue.Len(); i++ {
+ indexedValue, err := prettyPrint(propertyValue.Index(i), indent+1)
+ if err != nil {
+ return "", err
+ }
- if indexedValue != "" {
- ret += makeIndent(indent + 1)
- ret += indexedValue
- ret += ",\n"
+ if indexedValue != "" {
+ ret += makeIndent(indent + 1)
+ ret += indexedValue
+ ret += ",\n"
+ }
}
+ ret += makeIndent(indent)
+ ret += "]"
}
- ret += makeIndent(indent)
- ret += "]"
+
case reflect.Struct:
// Special cases where the bp2build sends additional information to the codegenerator
// by wrapping the attributes in a custom struct type.
- if labels, ok := propertyValue.Interface().(bazel.LabelListAttribute); ok {
- // TODO(b/165114590): convert glob syntax
- ret, err := prettyPrint(reflect.ValueOf(labels.Value.Includes), indent)
- if err != nil {
- return ret, err
- }
-
- if !labels.HasArchSpecificValues() {
- // Select statement not needed.
- return ret, nil
- }
-
- ret += " + " + "select({\n"
- for _, arch := range android.ArchTypeList() {
- value := labels.GetValueForArch(arch.Name)
- if len(value.Includes) > 0 {
- ret += makeIndent(indent + 1)
- list, _ := prettyPrint(reflect.ValueOf(value.Includes), indent+1)
- ret += fmt.Sprintf("\"%s\": %s,\n", platformArchMap[arch], list)
- }
- }
-
- ret += makeIndent(indent + 1)
- ret += fmt.Sprintf("\"%s\": [],\n", "//conditions:default")
-
- ret += makeIndent(indent)
- ret += "})"
- return ret, err
+ if attr, ok := propertyValue.Interface().(bazel.Attribute); ok {
+ return prettyPrintAttribute(attr, indent)
} else if label, ok := propertyValue.Interface().(bazel.Label); ok {
return fmt.Sprintf("%q", label.Label), nil
- } else if stringList, ok := propertyValue.Interface().(bazel.StringListAttribute); ok {
- // A Bazel string_list attribute that may contain a select statement.
- ret, err := prettyPrint(reflect.ValueOf(stringList.Value), indent)
- if err != nil {
- return ret, err
- }
-
- if !stringList.HasArchSpecificValues() {
- // Select statement not needed.
- return ret, nil
- }
-
- ret += " + " + "select({\n"
- for _, arch := range android.ArchTypeList() {
- value := stringList.GetValueForArch(arch.Name)
- if len(value) > 0 {
- ret += makeIndent(indent + 1)
- list, _ := prettyPrint(reflect.ValueOf(value), indent+1)
- ret += fmt.Sprintf("\"%s\": %s,\n", platformArchMap[arch], list)
- }
- }
-
- ret += makeIndent(indent + 1)
- ret += fmt.Sprintf("\"%s\": [],\n", "//conditions:default")
-
- ret += makeIndent(indent)
- ret += "})"
- return ret, err
}
ret = "{\n"
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index 49897b3..1ede442 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -27,9 +27,7 @@
expectedBazelTarget string
}{
{
- bp: `custom {
- name: "foo",
-}
+ bp: `custom { name: "foo" }
`,
expectedBazelTarget: `soong_module(
name = "foo",
@@ -85,9 +83,7 @@
soong_module_variant = "",
soong_module_deps = [
],
- required = [
- "bar",
- ],
+ required = ["bar"],
)`,
},
{
@@ -116,12 +112,10 @@
targets: ["goal_foo"],
tag: ".foo",
},
- dists: [
- {
- targets: ["goal_bar"],
- tag: ".bar",
- },
- ],
+ dists: [{
+ targets: ["goal_bar"],
+ tag: ".bar",
+ }],
}
`,
expectedBazelTarget: `soong_module(
@@ -133,18 +127,12 @@
],
dist = {
"tag": ".foo",
- "targets": [
- "goal_foo",
- ],
+ "targets": ["goal_foo"],
},
- dists = [
- {
- "tag": ".bar",
- "targets": [
- "goal_bar",
- ],
- },
- ],
+ dists = [{
+ "tag": ".bar",
+ "targets": ["goal_bar"],
+ }],
)`,
},
{
@@ -169,19 +157,13 @@
soong_module_variant = "",
soong_module_deps = [
],
- dists = [
- {
- "tag": ".tag",
- "targets": [
- "my_goal",
- ],
- },
- ],
+ dists = [{
+ "tag": ".tag",
+ "targets": ["my_goal"],
+ }],
owner = "custom_owner",
ramdisk = True,
- required = [
- "bar",
- ],
+ required = ["bar"],
target_required = [
"qux",
"bazqux",
@@ -553,9 +535,7 @@
}`,
expectedBazelTargets: []string{`filegroup(
name = "fg_foo",
- srcs = [
- "b",
- ],
+ srcs = ["b"],
)`,
},
},
@@ -625,7 +605,7 @@
bp: `filegroup {
name: "foobar",
srcs: [
- ":foo",
+ ":foo",
"c",
],
bazel_module: { bp2build_available: true },
@@ -671,25 +651,15 @@
`genrule(
name = "foo",
cmd = "$(location :foo.tool) --genDir=$(GENDIR) arg $(SRCS) $(OUTS)",
- outs = [
- "foo.out",
- ],
- srcs = [
- "foo.in",
- ],
- tools = [
- ":foo.tool",
- ],
+ outs = ["foo.out"],
+ srcs = ["foo.in"],
+ tools = [":foo.tool"],
)`,
`genrule(
name = "foo.tool",
cmd = "cp $(SRCS) $(OUTS)",
- outs = [
- "foo_tool.out",
- ],
- srcs = [
- "foo_tool.in",
- ],
+ outs = ["foo_tool.out"],
+ srcs = ["foo_tool.in"],
)`,
},
},
@@ -718,15 +688,9 @@
expectedBazelTargets: []string{`genrule(
name = "foo",
cmd = "$(locations :foo.tools) -s $(OUTS) $(SRCS)",
- outs = [
- "foo.out",
- ],
- srcs = [
- "foo.in",
- ],
- tools = [
- ":foo.tools",
- ],
+ outs = ["foo.out"],
+ srcs = ["foo.in"],
+ tools = [":foo.tools"],
)`,
`genrule(
name = "foo.tools",
@@ -735,9 +699,7 @@
"foo_tool.out",
"foo_tool2.out",
],
- srcs = [
- "foo_tool.in",
- ],
+ srcs = ["foo_tool.in"],
)`,
},
},
@@ -758,15 +720,9 @@
expectedBazelTargets: []string{`genrule(
name = "foo",
cmd = "$(locations //other:foo.tool) -s $(OUTS) $(SRCS)",
- outs = [
- "foo.out",
- ],
- srcs = [
- "foo.in",
- ],
- tools = [
- "//other:foo.tool",
- ],
+ outs = ["foo.out"],
+ srcs = ["foo.in"],
+ tools = ["//other:foo.tool"],
)`,
},
fs: otherGenruleBp,
@@ -788,15 +744,9 @@
expectedBazelTargets: []string{`genrule(
name = "foo",
cmd = "$(locations //other:foo.tool) -s $(OUTS) $(location //other:other.tool)",
- outs = [
- "foo.out",
- ],
- srcs = [
- "//other:other.tool",
- ],
- tools = [
- "//other:foo.tool",
- ],
+ outs = ["foo.out"],
+ srcs = ["//other:other.tool"],
+ tools = ["//other:foo.tool"],
)`,
},
fs: otherGenruleBp,
@@ -818,12 +768,8 @@
expectedBazelTargets: []string{`genrule(
name = "foo",
cmd = "$(location //other:foo.tool) -s $(OUTS) $(SRCS)",
- outs = [
- "foo.out",
- ],
- srcs = [
- "foo.in",
- ],
+ outs = ["foo.out"],
+ srcs = ["foo.in"],
tools = [
"//other:foo.tool",
"//other:other.tool",
@@ -849,12 +795,8 @@
expectedBazelTargets: []string{`genrule(
name = "foo",
cmd = "$(locations //other:foo.tool) -s $(OUTS) $(SRCS)",
- outs = [
- "foo.out",
- ],
- srcs = [
- "foo.in",
- ],
+ outs = ["foo.out"],
+ srcs = ["foo.in"],
tools = [
"//other:foo.tool",
"//other:other.tool",
@@ -879,12 +821,8 @@
expectedBazelTargets: []string{`genrule(
name = "foo",
cmd = "cp $(SRCS) $(OUTS)",
- outs = [
- "foo.out",
- ],
- srcs = [
- "foo.in",
- ],
+ outs = ["foo.out"],
+ srcs = ["foo.in"],
)`,
},
},
@@ -988,12 +926,8 @@
expectedBazelTarget: `genrule(
name = "gen",
cmd = "do-something $(SRCS) $(OUTS)",
- outs = [
- "out",
- ],
- srcs = [
- "in1",
- ],
+ outs = ["out"],
+ srcs = ["in1"],
)`,
description: "genrule applies properties from a genrule_defaults dependency if not specified",
},
@@ -1062,12 +996,8 @@
expectedBazelTarget: `genrule(
name = "gen",
cmd = "cp $(SRCS) $(OUTS)",
- outs = [
- "out",
- ],
- srcs = [
- "in1",
- ],
+ outs = ["out"],
+ srcs = ["in1"],
)`,
description: "genrule applies properties from list of genrule_defaults",
},
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
new file mode 100644
index 0000000..783af2e
--- /dev/null
+++ b/bp2build/cc_library_conversion_test.go
@@ -0,0 +1,271 @@
+// Copyright 2021 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package bp2build
+
+import (
+ "android/soong/android"
+ "android/soong/cc"
+ "strings"
+ "testing"
+)
+
+const (
+ // See cc/testing.go for more context
+ soongCcLibraryPreamble = `
+cc_defaults {
+ name: "linux_bionic_supported",
+}
+
+toolchain_library {
+ name: "libclang_rt.builtins-x86_64-android",
+ defaults: ["linux_bionic_supported"],
+ vendor_available: true,
+ vendor_ramdisk_available: true,
+ product_available: true,
+ recovery_available: true,
+ native_bridge_supported: true,
+ src: "",
+}`
+)
+
+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
+ }{
+ {
+ 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 + `
+cc_library_headers { name: "some-headers" }
+cc_library {
+ name: "foo-lib",
+ srcs: ["impl.cpp"],
+ cflags: ["-Wall"],
+ header_libs: ["some-headers"],
+ export_include_dirs: ["foo-dir"],
+ ldflags: ["-Wl,--exclude-libs=bar.a"],
+ arch: {
+ x86: {
+ ldflags: ["-Wl,--exclude-libs=baz.a"],
+ srcs: ["x86.cpp"],
+ },
+ x86_64: {
+ ldflags: ["-Wl,--exclude-libs=qux.a"],
+ srcs: ["x86_64.cpp"],
+ },
+ },
+ target: {
+ android: {
+ srcs: ["android.cpp"],
+ },
+ linux_glibc: {
+ srcs: ["linux.cpp"],
+ },
+ darwin: {
+ srcs: ["darwin.cpp"],
+ },
+ },
+}
+`,
+ expectedBazelTargets: []string{`cc_library(
+ name = "foo-lib",
+ copts = ["-Wall"],
+ deps = [":some-headers"],
+ hdrs = [
+ "header.h",
+ "header.hh",
+ "header.hpp",
+ "header.hxx",
+ "header.h++",
+ "header.inl",
+ "header.inc",
+ "header.ipp",
+ "header.h.generic",
+ "foo-dir/a.h",
+ ],
+ includes = ["foo-dir"],
+ linkopts = ["-Wl,--exclude-libs=bar.a"] + select({
+ "//build/bazel/platforms/arch:x86": ["-Wl,--exclude-libs=baz.a"],
+ "//build/bazel/platforms/arch:x86_64": ["-Wl,--exclude-libs=qux.a"],
+ "//conditions:default": [],
+ }),
+ srcs = ["impl.cpp"] + select({
+ "//build/bazel/platforms/arch:x86": ["x86.cpp"],
+ "//build/bazel/platforms/arch:x86_64": ["x86_64.cpp"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/platforms/os:android": ["android.cpp"],
+ "//build/bazel/platforms/os:darwin": ["darwin.cpp"],
+ "//build/bazel/platforms/os:linux": ["linux.cpp"],
+ "//conditions:default": [],
+ }),
+)`},
+ },
+ {
+ 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 + `
+cc_library_headers { name: "libc_headers" }
+cc_library {
+ name: "fake-ld-android",
+ srcs: ["ld_android.cpp"],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Wunused",
+ "-Werror",
+ ],
+ header_libs: ["libc_headers"],
+ ldflags: [
+ "-Wl,--exclude-libs=libgcc.a",
+ "-Wl,--exclude-libs=libgcc_stripped.a",
+ "-Wl,--exclude-libs=libclang_rt.builtins-arm-android.a",
+ "-Wl,--exclude-libs=libclang_rt.builtins-aarch64-android.a",
+ "-Wl,--exclude-libs=libclang_rt.builtins-i686-android.a",
+ "-Wl,--exclude-libs=libclang_rt.builtins-x86_64-android.a",
+ ],
+ arch: {
+ x86: {
+ ldflags: ["-Wl,--exclude-libs=libgcc_eh.a"],
+ },
+ x86_64: {
+ ldflags: ["-Wl,--exclude-libs=libgcc_eh.a"],
+ },
+ },
+}
+`,
+ expectedBazelTargets: []string{`cc_library(
+ name = "fake-ld-android",
+ copts = [
+ "-Wall",
+ "-Wextra",
+ "-Wunused",
+ "-Werror",
+ ],
+ deps = [":libc_headers"],
+ hdrs = [
+ "linked_list.h",
+ "linker.h",
+ "linker_block_allocator.h",
+ "linker_cfi.h",
+ ],
+ linkopts = [
+ "-Wl,--exclude-libs=libgcc.a",
+ "-Wl,--exclude-libs=libgcc_stripped.a",
+ "-Wl,--exclude-libs=libclang_rt.builtins-arm-android.a",
+ "-Wl,--exclude-libs=libclang_rt.builtins-aarch64-android.a",
+ "-Wl,--exclude-libs=libclang_rt.builtins-i686-android.a",
+ "-Wl,--exclude-libs=libclang_rt.builtins-x86_64-android.a",
+ ] + select({
+ "//build/bazel/platforms/arch:x86": ["-Wl,--exclude-libs=libgcc_eh.a"],
+ "//build/bazel/platforms/arch:x86_64": ["-Wl,--exclude-libs=libgcc_eh.a"],
+ "//conditions:default": [],
+ }),
+ srcs = ["ld_android.cpp"],
+)`},
+ },
+ }
+
+ 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)
+
+ cc.RegisterCCBuildComponents(ctx)
+ 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
+ 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_headers_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go
index 049f84a..c59241f 100644
--- a/bp2build/cc_library_headers_conversion_test.go
+++ b/bp2build/cc_library_headers_conversion_test.go
@@ -23,7 +23,7 @@
const (
// See cc/testing.go for more context
- soongCcLibraryPreamble = `
+ soongCcLibraryHeadersPreamble = `
cc_defaults {
name: "linux_bionic_supported",
}
@@ -37,17 +37,6 @@
recovery_available: true,
native_bridge_supported: true,
src: "",
-}
-
-toolchain_library {
- name: "libatomic",
- defaults: ["linux_bionic_supported"],
- vendor_available: true,
- vendor_ramdisk_available: true,
- product_available: true,
- recovery_available: true,
- native_bridge_supported: true,
- src: "",
}`
)
@@ -97,26 +86,27 @@
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": "",
+ "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: soongCcLibraryPreamble + `
+ bp: soongCcLibraryHeadersPreamble + `
cc_library_headers {
name: "lib-1",
export_include_dirs: ["lib-1"],
- bazel_module: { bp2build_available: true },
}
cc_library_headers {
name: "lib-2",
export_include_dirs: ["lib-2"],
- bazel_module: { bp2build_available: true },
}
cc_library_headers {
@@ -124,8 +114,20 @@
export_include_dirs: ["dir-1", "dir-2"],
header_libs: ["lib-1", "lib-2"],
+ arch: {
+ arm64: {
+ // We expect dir-1 headers to be dropped, because dir-1 is already in export_include_dirs
+ export_include_dirs: ["arch_arm64_exported_include_dir", "dir-1"],
+ },
+ x86: {
+ export_include_dirs: ["arch_x86_exported_include_dir"],
+ },
+ x86_64: {
+ export_include_dirs: ["arch_x86_64_exported_include_dir"],
+ },
+ },
+
// TODO: Also support export_header_lib_headers
- bazel_module: { bp2build_available: true },
}`,
expectedBazelTargets: []string{`cc_library_headers(
name = "foo_headers",
@@ -138,29 +140,121 @@
"dir-1/dir1b.h",
"dir-2/dir2a.h",
"dir-2/dir2b.h",
- ],
+ ] + select({
+ "//build/bazel/platforms/arch:arm64": ["arch_arm64_exported_include_dir/a.h"],
+ "//build/bazel/platforms/arch:x86": ["arch_x86_exported_include_dir/b.h"],
+ "//build/bazel/platforms/arch:x86_64": ["arch_x86_64_exported_include_dir/c.h"],
+ "//conditions:default": [],
+ }),
includes = [
"dir-1",
"dir-2",
- ],
+ ] + select({
+ "//build/bazel/platforms/arch:arm64": ["arch_arm64_exported_include_dir"],
+ "//build/bazel/platforms/arch:x86": ["arch_x86_exported_include_dir"],
+ "//build/bazel/platforms/arch:x86_64": ["arch_x86_64_exported_include_dir"],
+ "//conditions:default": [],
+ }),
)`, `cc_library_headers(
name = "lib-1",
hdrs = [
"lib-1/lib1a.h",
"lib-1/lib1b.h",
],
- includes = [
- "lib-1",
- ],
+ includes = ["lib-1"],
)`, `cc_library_headers(
name = "lib-2",
hdrs = [
"lib-2/lib2a.h",
"lib-2/lib2b.h",
],
- includes = [
- "lib-2",
- ],
+ 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 + `
+cc_library_headers { name: "android-lib" }
+cc_library_headers { name: "base-lib" }
+cc_library_headers { name: "darwin-lib" }
+cc_library_headers { name: "fuchsia-lib" }
+cc_library_headers { name: "linux-lib" }
+cc_library_headers { name: "linux_bionic-lib" }
+cc_library_headers { name: "windows-lib" }
+cc_library_headers {
+ name: "foo_headers",
+ header_libs: ["base-lib"],
+ target: {
+ android: { header_libs: ["android-lib"] },
+ darwin: { header_libs: ["darwin-lib"] },
+ fuchsia: { header_libs: ["fuchsia-lib"] },
+ linux_bionic: { header_libs: ["linux_bionic-lib"] },
+ linux_glibc: { header_libs: ["linux-lib"] },
+ windows: { header_libs: ["windows-lib"] },
+ },
+ bazel_module: { bp2build_available: true },
+}`,
+ expectedBazelTargets: []string{`cc_library_headers(
+ name = "android-lib",
+)`, `cc_library_headers(
+ name = "base-lib",
+)`, `cc_library_headers(
+ name = "darwin-lib",
+)`, `cc_library_headers(
+ name = "foo_headers",
+ 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"],
+ "//build/bazel/platforms/os:linux": [":linux-lib"],
+ "//build/bazel/platforms/os:linux_bionic": [":linux_bionic-lib"],
+ "//build/bazel/platforms/os:windows": [":windows-lib"],
+ "//conditions:default": [],
+ }),
+)`, `cc_library_headers(
+ name = "fuchsia-lib",
+)`, `cc_library_headers(
+ name = "linux-lib",
+)`, `cc_library_headers(
+ name = "linux_bionic-lib",
+)`, `cc_library_headers(
+ name = "windows-lib",
+)`},
+ },
+ {
+ 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 + `
+cc_library_headers { name: "android-lib" }
+cc_library_headers { name: "exported-lib" }
+cc_library_headers {
+ name: "foo_headers",
+ target: {
+ android: { header_libs: ["android-lib"], export_header_lib_headers: ["exported-lib"] },
+ },
+}`,
+ expectedBazelTargets: []string{`cc_library_headers(
+ name = "android-lib",
+)`, `cc_library_headers(
+ name = "exported-lib",
+)`, `cc_library_headers(
+ name = "foo_headers",
+ deps = select({
+ "//build/bazel/platforms/os:android": [
+ ":android-lib",
+ ":exported-lib",
+ ],
+ "//conditions:default": [],
+ }),
)`},
},
}
@@ -180,6 +274,9 @@
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)
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index 7bf5fd3..7e72a8b 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -37,17 +37,6 @@
recovery_available: true,
native_bridge_supported: true,
src: "",
-}
-
-toolchain_library {
- name: "libatomic",
- defaults: ["linux_bionic_supported"],
- vendor_available: true,
- vendor_ramdisk_available: true,
- product_available: true,
- recovery_available: true,
- native_bridge_supported: true,
- src: "",
}`
)
@@ -112,6 +101,9 @@
"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 + `
cc_library_headers {
@@ -202,6 +194,8 @@
":whole_static_lib_2",
],
hdrs = [
+ "implicit_include_1.h",
+ "implicit_include_2.h",
"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",
@@ -214,35 +208,121 @@
"include_dir_2",
"local_include_dir_1",
"local_include_dir_2",
+ ".",
],
linkstatic = True,
srcs = [
"foo_static1.cc",
"foo_static2.cc",
+ "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",
+ "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",
+ "implicit_include_1.h",
+ "implicit_include_2.h",
],
)`, `cc_library_static(
name = "static_lib_1",
+ hdrs = [
+ "implicit_include_1.h",
+ "implicit_include_2.h",
+ ],
+ includes = ["."],
linkstatic = True,
srcs = [
"static_lib_1.cc",
+ "implicit_include_1.h",
+ "implicit_include_2.h",
],
)`, `cc_library_static(
name = "static_lib_2",
+ hdrs = [
+ "implicit_include_1.h",
+ "implicit_include_2.h",
+ ],
+ includes = ["."],
linkstatic = True,
srcs = [
"static_lib_2.cc",
+ "implicit_include_1.h",
+ "implicit_include_2.h",
],
)`, `cc_library_static(
name = "whole_static_lib_1",
+ hdrs = [
+ "implicit_include_1.h",
+ "implicit_include_2.h",
+ ],
+ includes = ["."],
linkstatic = True,
srcs = [
"whole_static_lib_1.cc",
+ "implicit_include_1.h",
+ "implicit_include_2.h",
],
)`, `cc_library_static(
name = "whole_static_lib_2",
+ hdrs = [
+ "implicit_include_1.h",
+ "implicit_include_2.h",
+ ],
+ includes = ["."],
linkstatic = True,
srcs = [
"whole_static_lib_2.cc",
+ "implicit_include_1.h",
+ "implicit_include_2.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 + `
+cc_library_static {
+ name: "foo_static",
+ srcs: [
+ ],
+ include_dirs: [
+ "subpackage",
+ ],
+
+ bazel_module: { bp2build_available: true },
+}`,
+ expectedBazelTargets: []string{`cc_library_static(
+ name = "foo_static",
+ includes = [
+ "subpackage",
+ ".",
+ ],
+ linkstatic = True,
+ srcs = [
+ "//subpackage:subpackage_header.h",
+ "//subpackage:subdirectory/subdirectory_header.h",
+ "//subpackage/subsubpackage:subsubpackage_header.h",
+ "//subpackage/subsubpackage:subdirectory/subdirectory_header.h",
+ "//subpackage/subsubpackage/subsubsubpackage:subsubsubpackage_header.h",
+ "//subpackage/subsubpackage/subsubsubpackage:subdirectory/subdirectory_header.h",
],
)`},
},
diff --git a/bp2build/cc_object_conversion_test.go b/bp2build/cc_object_conversion_test.go
index 9461739..a9d24ac 100644
--- a/bp2build/cc_object_conversion_test.go
+++ b/bp2build/cc_object_conversion_test.go
@@ -52,7 +52,6 @@
"-Werror",
],
srcs: [
- "a/b/*.h",
"a/b/*.c"
],
exclude_srcs: ["a/b/exclude.c"],
@@ -68,15 +67,15 @@
"-Wall",
"-Werror",
],
+ hdrs = [
+ "a/b/bar.h",
+ "a/b/foo.h",
+ ],
local_include_dirs = [
"include",
".",
],
- srcs = [
- "a/b/bar.h",
- "a/b/c.c",
- "a/b/foo.h",
- ],
+ srcs = ["a/b/c.c"],
)`,
},
},
@@ -123,9 +122,7 @@
"include",
".",
],
- srcs = [
- "a/b/c.c",
- ],
+ srcs = ["a/b/c.c"],
)`,
},
},
@@ -155,29 +152,15 @@
`,
expectedBazelTargets: []string{`cc_object(
name = "bar",
- copts = [
- "-fno-addrsig",
- ],
- local_include_dirs = [
- ".",
- ],
- srcs = [
- "x/y/z.c",
- ],
+ copts = ["-fno-addrsig"],
+ local_include_dirs = ["."],
+ srcs = ["x/y/z.c"],
)`, `cc_object(
name = "foo",
- copts = [
- "-fno-addrsig",
- ],
- deps = [
- ":bar",
- ],
- local_include_dirs = [
- ".",
- ],
- srcs = [
- "a/b/c.c",
- ],
+ copts = ["-fno-addrsig"],
+ deps = [":bar"],
+ local_include_dirs = ["."],
+ srcs = ["a/b/c.c"],
)`,
},
},
@@ -200,12 +183,8 @@
`,
expectedBazelTargets: []string{`cc_object(
name = "foo",
- copts = [
- "-fno-addrsig",
- ],
- srcs = [
- "a/b/c.c",
- ],
+ copts = ["-fno-addrsig"],
+ srcs = ["a/b/c.c"],
)`,
},
},
@@ -228,12 +207,8 @@
`,
expectedBazelTargets: []string{`cc_object(
name = "foo",
- asflags = [
- "-DPLATFORM_SDK_VERSION={Platform_sdk_version}",
- ],
- copts = [
- "-fno-addrsig",
- ],
+ asflags = ["-DPLATFORM_SDK_VERSION={Platform_sdk_version}"],
+ copts = ["-fno-addrsig"],
)`,
},
},
@@ -321,23 +296,13 @@
expectedBazelTargets: []string{
`cc_object(
name = "foo",
- copts = [
- "-fno-addrsig",
- ] + select({
- "@bazel_tools//platforms:x86_32": [
- "-fPIC",
- ],
+ copts = ["-fno-addrsig"] + select({
+ "//build/bazel/platforms/arch:x86": ["-fPIC"],
"//conditions:default": [],
}),
- local_include_dirs = [
- ".",
- ],
- srcs = [
- "a.cpp",
- ] + select({
- "@bazel_tools//platforms:arm": [
- "arch/arm/file.S",
- ],
+ local_include_dirs = ["."],
+ srcs = ["a.cpp"] + select({
+ "//build/bazel/platforms/arch:arm": ["arch/arm/file.S"],
"//conditions:default": [],
}),
)`,
@@ -375,46 +340,60 @@
expectedBazelTargets: []string{
`cc_object(
name = "foo",
- copts = [
- "-fno-addrsig",
- ] + select({
- "@bazel_tools//platforms:arm": [
- "-Wall",
- ],
- "@bazel_tools//platforms:aarch64": [
- "-Wall",
- ],
- "@bazel_tools//platforms:x86_32": [
- "-fPIC",
- ],
- "@bazel_tools//platforms:x86_64": [
- "-fPIC",
- ],
+ copts = ["-fno-addrsig"] + select({
+ "//build/bazel/platforms/arch:arm": ["-Wall"],
+ "//build/bazel/platforms/arch:arm64": ["-Wall"],
+ "//build/bazel/platforms/arch:x86": ["-fPIC"],
+ "//build/bazel/platforms/arch:x86_64": ["-fPIC"],
"//conditions:default": [],
}),
- local_include_dirs = [
- ".",
- ],
- srcs = [
- "base.cpp",
- ] + select({
- "@bazel_tools//platforms:arm": [
- "arm.cpp",
- ],
- "@bazel_tools//platforms:aarch64": [
- "arm64.cpp",
- ],
- "@bazel_tools//platforms:x86_32": [
- "x86.cpp",
- ],
- "@bazel_tools//platforms:x86_64": [
- "x86_64.cpp",
- ],
+ local_include_dirs = ["."],
+ srcs = ["base.cpp"] + select({
+ "//build/bazel/platforms/arch:arm": ["arm.cpp"],
+ "//build/bazel/platforms/arch:arm64": ["arm64.cpp"],
+ "//build/bazel/platforms/arch:x86": ["x86.cpp"],
+ "//build/bazel/platforms/arch:x86_64": ["x86_64.cpp"],
"//conditions:default": [],
}),
)`,
},
},
+ {
+ 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: {
+ android: {
+ cflags: ["-fPIC"],
+ },
+ windows: {
+ cflags: ["-fPIC"],
+ },
+ darwin: {
+ cflags: ["-Wall"],
+ },
+ },
+ bazel_module: { bp2build_available: true },
+}
+`,
+ expectedBazelTargets: []string{
+ `cc_object(
+ name = "foo",
+ copts = ["-fno-addrsig"] + select({
+ "//build/bazel/platforms/os:android": ["-fPIC"],
+ "//build/bazel/platforms/os:darwin": ["-Wall"],
+ "//build/bazel/platforms/os:windows": ["-fPIC"],
+ "//conditions:default": [],
+ }),
+ local_include_dirs = ["."],
+ srcs = ["base.cpp"],
+)`,
+ },
+ },
}
dir := "."
diff --git a/bp2build/configurability.go b/bp2build/configurability.go
index 47cf3c6..97729df 100644
--- a/bp2build/configurability.go
+++ b/bp2build/configurability.go
@@ -1,15 +1,142 @@
package bp2build
-import "android/soong/android"
+import (
+ "android/soong/android"
+ "android/soong/bazel"
+ "fmt"
+ "reflect"
+)
// Configurability support for bp2build.
-var (
- // A map of architectures to the Bazel label of the constraint_value.
- platformArchMap = map[android.ArchType]string{
- android.Arm: "@bazel_tools//platforms:arm",
- android.Arm64: "@bazel_tools//platforms:aarch64",
- android.X86: "@bazel_tools//platforms:x86_32",
- android.X86_64: "@bazel_tools//platforms:x86_64",
+type selects map[string]reflect.Value
+
+func getStringListValues(list bazel.StringListAttribute) (reflect.Value, selects, selects) {
+ value := reflect.ValueOf(list.Value)
+ if !list.HasConfigurableValues() {
+ return value, nil, nil
}
-)
+
+ archSelects := map[string]reflect.Value{}
+ for arch, selectKey := range bazel.PlatformArchMap {
+ archSelects[selectKey] = reflect.ValueOf(list.GetValueForArch(arch))
+ }
+
+ osSelects := map[string]reflect.Value{}
+ for os, selectKey := range bazel.PlatformOsMap {
+ osSelects[selectKey] = reflect.ValueOf(list.GetValueForOS(os))
+ }
+
+ return value, archSelects, osSelects
+}
+
+func getLabelListValues(list bazel.LabelListAttribute) (reflect.Value, selects, selects) {
+ value := reflect.ValueOf(list.Value.Includes)
+ if !list.HasConfigurableValues() {
+ return value, nil, nil
+ }
+
+ archSelects := map[string]reflect.Value{}
+ for arch, selectKey := range bazel.PlatformArchMap {
+ archSelects[selectKey] = reflect.ValueOf(list.GetValueForArch(arch).Includes)
+ }
+
+ osSelects := map[string]reflect.Value{}
+ for os, selectKey := range bazel.PlatformOsMap {
+ osSelects[selectKey] = reflect.ValueOf(list.GetValueForOS(os).Includes)
+ }
+
+ return value, archSelects, osSelects
+}
+
+// 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
+
+ switch list := v.(type) {
+ case bazel.StringListAttribute:
+ value, archSelects, osSelects = getStringListValues(list)
+ case bazel.LabelListAttribute:
+ value, archSelects, osSelects = getLabelListValues(list)
+ default:
+ return "", fmt.Errorf("Not a supported Bazel attribute type: %s", v)
+ }
+
+ ret, err := prettyPrint(value, indent)
+ if err != nil {
+ return ret, err
+ }
+
+ // Convenience function to append selects components to an attribute value.
+ appendSelects := func(selectsData selects, defaultValue, s string) (string, error) {
+ selectMap, err := prettyPrintSelectMap(selectsData, defaultValue, indent)
+ if err != nil {
+ return "", err
+ }
+ if s != "" && selectMap != "" {
+ s += " + "
+ }
+ s += selectMap
+
+ return s, nil
+ }
+
+ ret, err = appendSelects(archSelects, "[]", ret)
+ if err != nil {
+ return "", err
+ }
+
+ ret, err = appendSelects(osSelects, "[]", ret)
+ return ret, err
+}
+
+// prettyPrintSelectMap converts a map of select keys to reflected Values as a generic way
+// to construct a select map for any kind of attribute type.
+func prettyPrintSelectMap(selectMap map[string]reflect.Value, defaultValue string, indent int) (string, error) {
+ if selectMap == nil {
+ return "", nil
+ }
+
+ var selects string
+ for _, selectKey := range android.SortedStringKeys(selectMap) {
+ value := selectMap[selectKey]
+ if isZero(value) {
+ // Ignore zero values to not generate empty lists.
+ continue
+ }
+ s, err := prettyPrintSelectEntry(value, selectKey, indent)
+ if err != nil {
+ return "", err
+ }
+ selects += s + ",\n"
+ }
+
+ if len(selects) == 0 {
+ // No conditions (or all values are empty lists), so no need for a map.
+ return "", nil
+ }
+
+ // Create the map.
+ ret := "select({\n"
+ ret += selects
+ // default condition comes last.
+ ret += fmt.Sprintf("%s\"%s\": %s,\n", makeIndent(indent+1), "//conditions:default", defaultValue)
+ ret += makeIndent(indent)
+ ret += "})"
+
+ return ret, nil
+}
+
+// prettyPrintSelectEntry converts a reflect.Value into an entry in a select map
+// with a provided key.
+func prettyPrintSelectEntry(value reflect.Value, key string, indent int) (string, error) {
+ s := makeIndent(indent + 1)
+ v, err := prettyPrint(value, indent+1)
+ if err != nil {
+ return "", err
+ }
+ s += fmt.Sprintf("\"%s\": %s", key, v)
+ return s, nil
+}
diff --git a/bp2build/python_binary_conversion_test.go b/bp2build/python_binary_conversion_test.go
index 7600e36..2054e06 100644
--- a/bp2build/python_binary_conversion_test.go
+++ b/bp2build/python_binary_conversion_test.go
@@ -33,24 +33,15 @@
blueprint: `python_binary_host {
name: "foo",
main: "a.py",
- srcs: [
- "**/*.py"
- ],
- exclude_srcs: [
- "b/e.py"
- ],
- data: [
- "files/data.txt",
- ],
-
+ srcs: ["**/*.py"],
+ exclude_srcs: ["b/e.py"],
+ data: ["files/data.txt",],
bazel_module: { bp2build_available: true },
}
`,
expectedBazelTargets: []string{`py_binary(
name = "foo",
- data = [
- "files/data.txt",
- ],
+ data = ["files/data.txt"],
main = "a.py",
srcs = [
"a.py",
@@ -83,9 +74,7 @@
expectedBazelTargets: []string{`py_binary(
name = "foo",
python_version = "PY2",
- srcs = [
- "a.py",
- ],
+ srcs = ["a.py"],
)`,
},
},
@@ -113,9 +102,7 @@
// python_version is PY3 by default.
`py_binary(
name = "foo",
- srcs = [
- "a.py",
- ],
+ srcs = ["a.py"],
)`,
},
},
diff --git a/bp2build/sh_conversion_test.go b/bp2build/sh_conversion_test.go
index 2aa373c..37f542e 100644
--- a/bp2build/sh_conversion_test.go
+++ b/bp2build/sh_conversion_test.go
@@ -74,9 +74,7 @@
}`,
expectedBazelTargets: []string{`sh_binary(
name = "foo",
- srcs = [
- "foo.sh",
- ],
+ srcs = ["foo.sh"],
)`},
},
}
diff --git a/bp2build/testing.go b/bp2build/testing.go
index ede8044..ef3a78f 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -5,6 +5,13 @@
"android/soong/bazel"
)
+var (
+ // A default configuration for tests to not have to specify bp2build_available on top level targets.
+ bp2buildConfig = android.Bp2BuildConfig{
+ android.BP2BUILD_TOPLEVEL: android.Bp2BuildDefaultTrueRecursively,
+ }
+)
+
type nestedProps struct {
Nested_prop string
}
diff --git a/cc/Android.bp b/cc/Android.bp
index 79e92cb..cc4d9bc 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -20,6 +20,7 @@
"androidmk.go",
"api_level.go",
"builder.go",
+ "bp2build.go",
"cc.go",
"ccdeps.go",
"check.go",
diff --git a/cc/api_level.go b/cc/api_level.go
index c93d6ed..fd145a9 100644
--- a/cc/api_level.go
+++ b/cc/api_level.go
@@ -53,14 +53,6 @@
return value, nil
}
-func nativeApiLevelFromUserWithDefault(ctx android.BaseModuleContext,
- raw string, defaultValue string) (android.ApiLevel, error) {
- if raw == "" {
- raw = defaultValue
- }
- return nativeApiLevelFromUser(ctx, raw)
-}
-
func nativeApiLevelOrPanic(ctx android.BaseModuleContext,
raw string) android.ApiLevel {
value, err := nativeApiLevelFromUser(ctx, raw)
diff --git a/cc/bp2build.go b/cc/bp2build.go
new file mode 100644
index 0000000..0bca30a
--- /dev/null
+++ b/cc/bp2build.go
@@ -0,0 +1,226 @@
+// 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 (
+ "android/soong/android"
+ "android/soong/bazel"
+ "strings"
+)
+
+// bp2build functions and helpers for converting cc_* modules to Bazel.
+
+func init() {
+ android.DepsBp2BuildMutators(RegisterDepsBp2Build)
+}
+
+func RegisterDepsBp2Build(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("cc_bp2build_deps", depsBp2BuildMutator)
+}
+
+// A naive deps mutator to add deps on all modules across all combinations of
+// target props for cc modules. This is needed to make module -> bazel label
+// resolution work in the bp2build mutator later. This is probably
+// the wrong way to do it, but it works.
+//
+// TODO(jingwen): can we create a custom os mutator in depsBp2BuildMutator to do this?
+func depsBp2BuildMutator(ctx android.BottomUpMutatorContext) {
+ module, ok := ctx.Module().(*Module)
+ if !ok {
+ // Not a cc module
+ return
+ }
+
+ if !module.ConvertWithBp2build(ctx) {
+ return
+ }
+
+ var allDeps []string
+
+ for _, p := range module.GetTargetProperties(&BaseLinkerProperties{}) {
+ // arch specific linker props
+ if baseLinkerProps, ok := p.(*BaseLinkerProperties); ok {
+ allDeps = append(allDeps, baseLinkerProps.Header_libs...)
+ allDeps = append(allDeps, baseLinkerProps.Export_header_lib_headers...)
+ }
+ }
+
+ ctx.AddDependency(module, nil, android.SortedUniqueStrings(allDeps)...)
+}
+
+// Convenience struct to hold all attributes parsed from compiler properties.
+type compilerAttributes struct {
+ copts bazel.StringListAttribute
+ srcs bazel.LabelListAttribute
+ hdrs bazel.LabelListAttribute
+}
+
+// bp2BuildParseCompilerProps returns copts, srcs and hdrs and other attributes.
+func bp2BuildParseCompilerProps(ctx android.TopDownMutatorContext, module *Module) compilerAttributes {
+ var hdrs, srcs bazel.LabelListAttribute
+ var copts bazel.StringListAttribute
+
+ hdrsAndSrcs := func(baseCompilerProps *BaseCompilerProperties) (bazel.LabelList, bazel.LabelList) {
+ srcsList := android.BazelLabelForModuleSrcExcludes(
+ ctx, baseCompilerProps.Srcs, baseCompilerProps.Exclude_srcs)
+ hdrsList := android.BazelLabelForModuleSrc(ctx, srcsList.LooseHdrsGlobs(headerExts))
+ return hdrsList, srcsList
+ }
+
+ for _, props := range module.compiler.compilerProps() {
+ if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
+ hdrs.Value, srcs.Value = hdrsAndSrcs(baseCompilerProps)
+ copts.Value = baseCompilerProps.Cflags
+ break
+ }
+ }
+
+ for arch, props := range module.GetArchProperties(&BaseCompilerProperties{}) {
+ if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
+ hdrsList, srcsList := hdrsAndSrcs(baseCompilerProps)
+ hdrs.SetValueForArch(arch.Name, bazel.SubtractBazelLabelList(hdrsList, hdrs.Value))
+ srcs.SetValueForArch(arch.Name, srcsList)
+ copts.SetValueForArch(arch.Name, baseCompilerProps.Cflags)
+ }
+ }
+
+ for os, props := range module.GetTargetProperties(&BaseCompilerProperties{}) {
+ if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
+ hdrsList, srcsList := hdrsAndSrcs(baseCompilerProps)
+ hdrs.SetValueForOS(os.Name, bazel.SubtractBazelLabelList(hdrsList, hdrs.Value))
+ srcs.SetValueForOS(os.Name, srcsList)
+ copts.SetValueForOS(os.Name, baseCompilerProps.Cflags)
+ }
+ }
+
+ return compilerAttributes{
+ hdrs: hdrs,
+ srcs: srcs,
+ copts: copts,
+ }
+}
+
+// Convenience struct to hold all attributes parsed from linker properties.
+type linkerAttributes struct {
+ deps bazel.LabelListAttribute
+ linkopts bazel.StringListAttribute
+}
+
+// bp2BuildParseLinkerProps creates a label list attribute containing the header library deps of a module, including
+// configurable attribute values.
+func bp2BuildParseLinkerProps(ctx android.TopDownMutatorContext, module *Module) linkerAttributes {
+
+ var deps bazel.LabelListAttribute
+ var linkopts bazel.StringListAttribute
+
+ for _, linkerProps := range module.linker.linkerProps() {
+ if baseLinkerProps, ok := linkerProps.(*BaseLinkerProperties); ok {
+ libs := baseLinkerProps.Header_libs
+ libs = append(libs, baseLinkerProps.Export_header_lib_headers...)
+ deps = bazel.MakeLabelListAttribute(
+ android.BazelLabelForModuleDeps(ctx, android.SortedUniqueStrings(libs)))
+ linkopts.Value = baseLinkerProps.Ldflags
+ break
+ }
+ }
+
+ for arch, p := range module.GetArchProperties(&BaseLinkerProperties{}) {
+ if baseLinkerProps, ok := p.(*BaseLinkerProperties); ok {
+ libs := baseLinkerProps.Header_libs
+ libs = append(libs, baseLinkerProps.Export_header_lib_headers...)
+ libs = android.SortedUniqueStrings(libs)
+ deps.SetValueForArch(arch.Name, android.BazelLabelForModuleDeps(ctx, libs))
+ linkopts.SetValueForArch(arch.Name, baseLinkerProps.Ldflags)
+ }
+ }
+
+ 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 = android.SortedUniqueStrings(libs)
+ deps.SetValueForOS(os.Name, android.BazelLabelForModuleDeps(ctx, libs))
+ linkopts.SetValueForOS(os.Name, baseLinkerProps.Ldflags)
+ }
+ }
+
+ return linkerAttributes{
+ deps: deps,
+ linkopts: linkopts,
+ }
+}
+
+func bp2BuildListHeadersInDir(ctx android.TopDownMutatorContext, includeDir string) bazel.LabelList {
+ globs := bazel.GlobsInDir(includeDir, includeDir != ".", headerExts)
+ return android.BazelLabelForModuleSrc(ctx, globs)
+}
+
+// Bazel wants include paths to be relative to the module
+func bp2BuildMakePathsRelativeToModule(ctx android.TopDownMutatorContext, paths []string) []string {
+ var relativePaths []string
+ for _, path := range paths {
+ relativePath := strings.TrimPrefix(path, ctx.ModuleDir()+"/")
+ relativePaths = append(relativePaths, relativePath)
+ }
+ return relativePaths
+}
+
+// bp2BuildParseExportedIncludes creates a label list attribute contains the
+// exported included directories of a module.
+func bp2BuildParseExportedIncludes(ctx android.TopDownMutatorContext, module *Module) (bazel.StringListAttribute, bazel.LabelListAttribute) {
+ libraryDecorator := module.linker.(*libraryDecorator)
+
+ includeDirs := libraryDecorator.flagExporter.Properties.Export_system_include_dirs
+ includeDirs = append(includeDirs, libraryDecorator.flagExporter.Properties.Export_include_dirs...)
+ includeDirs = bp2BuildMakePathsRelativeToModule(ctx, includeDirs)
+ includeDirsAttribute := bazel.MakeStringListAttribute(includeDirs)
+
+ var headersAttribute bazel.LabelListAttribute
+ var headers bazel.LabelList
+ for _, includeDir := range includeDirs {
+ headers.Append(bp2BuildListHeadersInDir(ctx, includeDir))
+ }
+ headers = bazel.UniqueBazelLabelList(headers)
+ headersAttribute.Value = headers
+
+ for arch, props := range module.GetArchProperties(&FlagExporterProperties{}) {
+ if flagExporterProperties, ok := props.(*FlagExporterProperties); ok {
+ archIncludeDirs := flagExporterProperties.Export_system_include_dirs
+ archIncludeDirs = append(archIncludeDirs, flagExporterProperties.Export_include_dirs...)
+ archIncludeDirs = bp2BuildMakePathsRelativeToModule(ctx, archIncludeDirs)
+
+ // To avoid duplicate includes when base includes + arch includes are combined
+ archIncludeDirs = bazel.SubtractStrings(archIncludeDirs, includeDirs)
+
+ if len(archIncludeDirs) > 0 {
+ includeDirsAttribute.SetValueForArch(arch.Name, archIncludeDirs)
+ }
+
+ var archHeaders bazel.LabelList
+ for _, archIncludeDir := range archIncludeDirs {
+ archHeaders.Append(bp2BuildListHeadersInDir(ctx, archIncludeDir))
+ }
+ archHeaders = bazel.UniqueBazelLabelList(archHeaders)
+
+ // To avoid duplicate headers when base headers + arch headers are combined
+ archHeaders = bazel.SubtractBazelLabelList(archHeaders, headers)
+
+ if len(archHeaders.Includes) > 0 || len(archHeaders.Excludes) > 0 {
+ headersAttribute.SetValueForArch(arch.Name, archHeaders)
+ }
+ }
+ }
+
+ return includeDirsAttribute, headersAttribute
+}
diff --git a/cc/builder.go b/cc/builder.go
index 8c9743f..da8501c 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -132,7 +132,7 @@
blueprint.RuleParams{
Depfile: "${out}.d",
Deps: blueprint.DepsGCC,
- Command: "CROSS_COMPILE=$crossCompile XZ=$xzCmd CLANG_BIN=${config.ClangBin} $stripPath ${args} -i ${in} -o ${out} -d ${out}.d",
+ Command: "XZ=$xzCmd CLANG_BIN=${config.ClangBin} $stripPath ${args} -i ${in} -o ${out} -d ${out}.d",
CommandDeps: []string{"$stripPath", "$xzCmd"},
Pool: darwinStripPool,
},
diff --git a/cc/cc.go b/cc/cc.go
index bef89fa..7f69d56 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -56,8 +56,8 @@
ctx.TopDown("asan_deps", sanitizerDepsMutator(Asan))
ctx.BottomUp("asan", sanitizerMutator(Asan)).Parallel()
- ctx.TopDown("hwasan_deps", sanitizerDepsMutator(hwasan))
- ctx.BottomUp("hwasan", sanitizerMutator(hwasan)).Parallel()
+ ctx.TopDown("hwasan_deps", sanitizerDepsMutator(Hwasan))
+ ctx.BottomUp("hwasan", sanitizerMutator(Hwasan)).Parallel()
ctx.TopDown("fuzzer_deps", sanitizerDepsMutator(Fuzzer))
ctx.BottomUp("fuzzer", sanitizerMutator(Fuzzer)).Parallel()
@@ -1113,16 +1113,33 @@
return inList(c.BaseModuleName(), *getNDKKnownLibs(config))
}
-// isLLndk returns true for both LLNDK (public) and LLNDK-private libs.
func (c *Module) IsLlndk() bool {
return c.VendorProperties.IsLLNDK
}
-// IsLlndkPublic returns true only for LLNDK (public) libs.
func (c *Module) IsLlndkPublic() bool {
return c.VendorProperties.IsLLNDK && !c.VendorProperties.IsVNDKPrivate
}
+func (c *Module) IsLlndkHeaders() bool {
+ if _, ok := c.linker.(*llndkHeadersDecorator); ok {
+ return true
+ }
+ return false
+}
+
+func (c *Module) IsLlndkLibrary() bool {
+ if _, ok := c.linker.(*llndkStubDecorator); ok {
+ return true
+ }
+ return false
+}
+
+func (m *Module) HasLlndkStubs() bool {
+ lib := moduleLibraryInterface(m)
+ return lib != nil && lib.hasLLNDKStubs()
+}
+
// 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 {
@@ -1186,6 +1203,10 @@
return false
}
+func (c *Module) SubName() string {
+ return c.Properties.SubName
+}
+
func (c *Module) MustUseVendorVariant() bool {
return c.isVndkSp() || c.Properties.MustUseVendorVariant
}
@@ -1246,7 +1267,7 @@
return c.linker != nil && c.linker.nativeCoverage()
}
-func (c *Module) isSnapshotPrebuilt() bool {
+func (c *Module) IsSnapshotPrebuilt() bool {
if p, ok := c.linker.(snapshotInterface); ok {
return p.isSnapshotPrebuilt()
}
@@ -1646,12 +1667,12 @@
c.hideApexVariantFromMake = true
}
+ c.makeLinkType = GetMakeLinkType(actx, c)
+
if c.maybeGenerateBazelActions(actx) {
return
}
- c.makeLinkType = GetMakeLinkType(actx, c)
-
ctx := &moduleContext{
ModuleContext: actx,
moduleContextImpl: moduleContextImpl{
@@ -2289,12 +2310,7 @@
if ccFrom.vndkdep != nil {
ccFrom.vndkdep.vndkCheckLinkType(ctx, ccTo, tag)
}
- } else if linkableMod, ok := to.(LinkableInterface); ok {
- // Static libraries from other languages can be linked
- if !linkableMod.Static() {
- ctx.ModuleErrorf("Attempting to link VNDK cc.Module with unsupported module type")
- }
- } else {
+ } else if _, ok := to.(LinkableInterface); !ok {
ctx.ModuleErrorf("Attempting to link VNDK cc.Module with unsupported module type")
}
return
@@ -2483,7 +2499,7 @@
c.apexSdkVersion = android.FutureApiLevel
apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
if !apexInfo.IsForPlatform() {
- c.apexSdkVersion = apexInfo.MinSdkVersion(ctx)
+ c.apexSdkVersion = apexInfo.MinSdkVersion
}
if android.InList("hwaddress", ctx.Config().SanitizeDevice()) {
@@ -2807,7 +2823,7 @@
c.sabi.Properties.ReexportedIncludes, depExporterInfo.IncludeDirs.Strings()...)
}
- makeLibName := c.makeLibName(ctx, ccDep, depName) + libDepTag.makeSuffix
+ makeLibName := MakeLibName(ctx, c, ccDep, depName) + libDepTag.makeSuffix
switch {
case libDepTag.header():
c.Properties.AndroidMkHeaderLibs = append(
@@ -2846,7 +2862,7 @@
switch depTag {
case runtimeDepTag:
c.Properties.AndroidMkRuntimeLibs = append(
- c.Properties.AndroidMkRuntimeLibs, c.makeLibName(ctx, ccDep, depName)+libDepTag.makeSuffix)
+ c.Properties.AndroidMkRuntimeLibs, MakeLibName(ctx, c, ccDep, depName)+libDepTag.makeSuffix)
// Record baseLibName for snapshots.
c.Properties.SnapshotRuntimeLibs = append(c.Properties.SnapshotRuntimeLibs, baseLibName(depName))
case objDepTag:
@@ -2924,7 +2940,8 @@
return libName
}
-func (c *Module) makeLibName(ctx android.ModuleContext, ccDep LinkableInterface, depName string) string {
+func MakeLibName(ctx android.ModuleContext, c LinkableInterface, ccDep LinkableInterface, depName string) string {
+
vendorPublicLibraries := vendorPublicLibraries(ctx.Config())
libName := baseLibName(depName)
@@ -2934,6 +2951,7 @@
nonSystemVariantsExist := ccDep.HasNonSystemVariants() || isLLndk
if ccDepModule != nil {
+ // TODO(ivanlozano) Support snapshots for Rust-produced C library variants.
// Use base module name for snapshots when exporting to Makefile.
if snapshotPrebuilt, ok := ccDepModule.linker.(snapshotInterface); ok {
baseName := ccDepModule.BaseModuleName()
@@ -2947,10 +2965,10 @@
// The vendor module is a no-vendor-variant VNDK library. Depend on the
// core module instead.
return libName
- } else if ccDep.UseVndk() && nonSystemVariantsExist && ccDepModule != nil {
+ } else if ccDep.UseVndk() && nonSystemVariantsExist {
// The vendor and product modules in Make will have been renamed to not conflict with the
// core module, so update the dependency name here accordingly.
- return libName + ccDepModule.Properties.SubName
+ return libName + ccDep.SubName()
} else if (ctx.Platform() || ctx.ProductSpecific()) && isVendorPublicLib {
return libName + vendorPublicLibrarySuffix
} else if ccDep.InRamdisk() && !ccDep.OnlyInRamdisk() {
@@ -3284,6 +3302,10 @@
type Defaults struct {
android.ModuleBase
android.DefaultsModuleBase
+ // Included to support setting bazel_module.label for multiple Soong modules to the same Bazel
+ // target. This is primarily useful for modules that were architecture specific and instead are
+ // handled in Bazel as a select().
+ android.BazelModuleBase
android.ApexModuleBase
}
@@ -3330,6 +3352,8 @@
&RustBindgenClangProperties{},
)
+ // Bazel module must be initialized _before_ Defaults to be included in cc_defaults module.
+ android.InitBazelModule(module)
android.InitDefaultsModule(module)
return module
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 76e75da..07dcc95 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -35,7 +35,7 @@
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
variables.DeviceVndkVersion = StringPtr("current")
variables.ProductVndkVersion = StringPtr("current")
- variables.Platform_vndk_version = StringPtr("VER")
+ variables.Platform_vndk_version = StringPtr("29")
}),
)
@@ -75,7 +75,7 @@
func testCcNoVndk(t *testing.T, bp string) *android.TestContext {
t.Helper()
config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
- config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("29")
return testCcWithConfig(t, config)
}
@@ -89,7 +89,7 @@
t.Helper()
config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
- config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("29")
return testCcWithConfig(t, config)
}
@@ -116,7 +116,7 @@
t.Helper()
config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
- config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("29")
testCcErrorWithConfig(t, pattern, config)
return
}
@@ -131,15 +131,15 @@
config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
config.TestProductVariables.ProductVndkVersion = StringPtr("current")
- config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("29")
testCcErrorWithConfig(t, pattern, config)
return
}
const (
coreVariant = "android_arm64_armv8-a_shared"
- vendorVariant = "android_vendor.VER_arm64_armv8-a_shared"
- productVariant = "android_product.VER_arm64_armv8-a_shared"
+ vendorVariant = "android_vendor.29_arm64_armv8-a_shared"
+ productVariant = "android_product.29_arm64_armv8-a_shared"
recoveryVariant = "android_recovery_arm64_armv8-a_shared"
)
@@ -244,6 +244,120 @@
}
}
+func checkInstallPartition(t *testing.T, ctx *android.TestContext, name, variant, expected string) {
+ mod := ctx.ModuleForTests(name, variant).Module().(*Module)
+ partitionDefined := false
+ checkPartition := func(specific bool, partition string) {
+ if specific {
+ if expected != partition && !partitionDefined {
+ // The variant is installed to the 'partition'
+ t.Errorf("%s variant of %q must not be installed to %s partition", variant, name, partition)
+ }
+ partitionDefined = true
+ } else {
+ // The variant is not installed to the 'partition'
+ if expected == partition {
+ t.Errorf("%s variant of %q must be installed to %s partition", variant, name, partition)
+ }
+ }
+ }
+ socSpecific := func(m *Module) bool {
+ return m.SocSpecific() || m.socSpecificModuleContext()
+ }
+ deviceSpecific := func(m *Module) bool {
+ return m.DeviceSpecific() || m.deviceSpecificModuleContext()
+ }
+ productSpecific := func(m *Module) bool {
+ return m.ProductSpecific() || m.productSpecificModuleContext()
+ }
+ systemExtSpecific := func(m *Module) bool {
+ return m.SystemExtSpecific()
+ }
+ checkPartition(socSpecific(mod), "vendor")
+ checkPartition(deviceSpecific(mod), "odm")
+ checkPartition(productSpecific(mod), "product")
+ checkPartition(systemExtSpecific(mod), "system_ext")
+ if !partitionDefined && expected != "system" {
+ t.Errorf("%s variant of %q is expected to be installed to %s partition,"+
+ " but installed to system partition", variant, name, expected)
+ }
+}
+
+func TestInstallPartition(t *testing.T) {
+ t.Helper()
+ ctx := prepareForCcTest.RunTestWithBp(t, `
+ cc_library {
+ name: "libsystem",
+ }
+ cc_library {
+ name: "libsystem_ext",
+ system_ext_specific: true,
+ }
+ cc_library {
+ name: "libproduct",
+ product_specific: true,
+ }
+ cc_library {
+ name: "libvendor",
+ vendor: true,
+ }
+ cc_library {
+ name: "libodm",
+ device_specific: true,
+ }
+ cc_library {
+ name: "liball_available",
+ vendor_available: true,
+ product_available: true,
+ }
+ cc_library {
+ name: "libsystem_ext_all_available",
+ system_ext_specific: true,
+ vendor_available: true,
+ product_available: true,
+ }
+ cc_library {
+ name: "liball_available_odm",
+ odm_available: true,
+ product_available: true,
+ }
+ cc_library {
+ name: "libproduct_vendoravailable",
+ product_specific: true,
+ vendor_available: true,
+ }
+ cc_library {
+ name: "libproduct_odmavailable",
+ product_specific: true,
+ odm_available: true,
+ }
+ `).TestContext
+
+ checkInstallPartition(t, ctx, "libsystem", coreVariant, "system")
+ checkInstallPartition(t, ctx, "libsystem_ext", coreVariant, "system_ext")
+ checkInstallPartition(t, ctx, "libproduct", productVariant, "product")
+ checkInstallPartition(t, ctx, "libvendor", vendorVariant, "vendor")
+ checkInstallPartition(t, ctx, "libodm", vendorVariant, "odm")
+
+ checkInstallPartition(t, ctx, "liball_available", coreVariant, "system")
+ checkInstallPartition(t, ctx, "liball_available", productVariant, "product")
+ checkInstallPartition(t, ctx, "liball_available", vendorVariant, "vendor")
+
+ checkInstallPartition(t, ctx, "libsystem_ext_all_available", coreVariant, "system_ext")
+ checkInstallPartition(t, ctx, "libsystem_ext_all_available", productVariant, "product")
+ checkInstallPartition(t, ctx, "libsystem_ext_all_available", vendorVariant, "vendor")
+
+ checkInstallPartition(t, ctx, "liball_available_odm", coreVariant, "system")
+ checkInstallPartition(t, ctx, "liball_available_odm", productVariant, "product")
+ checkInstallPartition(t, ctx, "liball_available_odm", vendorVariant, "odm")
+
+ checkInstallPartition(t, ctx, "libproduct_vendoravailable", productVariant, "product")
+ checkInstallPartition(t, ctx, "libproduct_vendoravailable", vendorVariant, "vendor")
+
+ checkInstallPartition(t, ctx, "libproduct_odmavailable", productVariant, "product")
+ checkInstallPartition(t, ctx, "libproduct_odmavailable", vendorVariant, "odm")
+}
+
func checkVndkModule(t *testing.T, ctx *android.TestContext, name, subDir string,
isVndkSp bool, extends string, variant string) {
@@ -456,7 +570,7 @@
config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
config.TestProductVariables.ProductVndkVersion = StringPtr("current")
- config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("29")
ctx := testCcWithConfig(t, config)
@@ -486,8 +600,8 @@
vndkCoreLib2ndPath := filepath.Join(vndkLib2ndPath, "shared", "vndk-core")
vndkSpLib2ndPath := filepath.Join(vndkLib2ndPath, "shared", "vndk-sp")
- variant := "android_vendor.VER_arm64_armv8-a_shared"
- variant2nd := "android_vendor.VER_arm_armv7-a-neon_shared"
+ variant := "android_vendor.29_arm64_armv8-a_shared"
+ variant2nd := "android_vendor.29_arm_armv7-a-neon_shared"
snapshotSingleton := ctx.SingletonForTests("vndk-snapshot")
@@ -577,12 +691,12 @@
}`
config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
- config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("29")
ctx := testCcWithConfig(t, config)
module := ctx.ModuleForTests("llndk.libraries.txt", "")
entries := android.AndroidMkEntriesForTest(t, ctx, module.Module())[0]
- assertArrayString(t, entries.EntryMap["LOCAL_MODULE_STEM"], []string{"llndk.libraries.VER.txt"})
+ assertArrayString(t, entries.EntryMap["LOCAL_MODULE_STEM"], []string{"llndk.libraries.29.txt"})
}
func TestVndkUsingCoreVariant(t *testing.T) {
@@ -627,7 +741,7 @@
config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
- config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("29")
config.TestProductVariables.VndkUseCoreVariant = BoolPtr(true)
setVndkMustUseVendorVariantListForTest(config, []string{"libvndk"})
@@ -654,7 +768,7 @@
config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
- config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("29")
config.TestProductVariables.VndkUseCoreVariant = BoolPtr(true)
ctx := testCcWithConfig(t, config)
@@ -705,7 +819,7 @@
config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
- config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("29")
config.TestProductVariables.VndkUseCoreVariant = BoolPtr(true)
ctx := testCcWithConfig(t, config)
@@ -1331,7 +1445,7 @@
config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
config.TestProductVariables.ProductVndkVersion = StringPtr("current")
- config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("29")
ctx := testCcWithConfig(t, config)
@@ -1776,7 +1890,7 @@
config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
config.TestProductVariables.ProductVndkVersion = StringPtr("current")
- config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("29")
testCcWithConfig(t, config)
}
@@ -2140,7 +2254,7 @@
}
func TestEnforceProductVndkVersionErrors(t *testing.T) {
- testCcErrorProductVndk(t, "dependency \".*\" of \".*\" missing variant:\n.*image:product.VER", `
+ testCcErrorProductVndk(t, "dependency \".*\" of \".*\" missing variant:\n.*image:product.29", `
cc_library {
name: "libprod",
product_specific: true,
@@ -2155,7 +2269,7 @@
nocrt: true,
}
`)
- testCcErrorProductVndk(t, "dependency \".*\" of \".*\" missing variant:\n.*image:product.VER", `
+ testCcErrorProductVndk(t, "dependency \".*\" of \".*\" missing variant:\n.*image:product.29", `
cc_library {
name: "libprod",
product_specific: true,
@@ -2169,7 +2283,7 @@
nocrt: true,
}
`)
- testCcErrorProductVndk(t, "dependency \".*\" of \".*\" missing variant:\n.*image:product.VER", `
+ testCcErrorProductVndk(t, "dependency \".*\" of \".*\" missing variant:\n.*image:product.29", `
cc_library {
name: "libprod",
product_specific: true,
@@ -2204,7 +2318,7 @@
nocrt: true,
}
`)
- testCcErrorProductVndk(t, "dependency \".*\" of \".*\" missing variant:\n.*image:product.VER", `
+ testCcErrorProductVndk(t, "dependency \".*\" of \".*\" missing variant:\n.*image:product.29", `
cc_library {
name: "libprod",
product_specific: true,
@@ -2330,7 +2444,7 @@
config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
- config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("29")
// native:vndk
ctx := testCcWithConfig(t, config)
@@ -2664,27 +2778,27 @@
`)
actual := ctx.ModuleVariantsForTests("libllndk")
for i := 0; i < len(actual); i++ {
- if !strings.HasPrefix(actual[i], "android_vendor.VER_") {
+ if !strings.HasPrefix(actual[i], "android_vendor.29_") {
actual = append(actual[:i], actual[i+1:]...)
i--
}
}
expected := []string{
- "android_vendor.VER_arm64_armv8-a_shared_1",
- "android_vendor.VER_arm64_armv8-a_shared_2",
- "android_vendor.VER_arm64_armv8-a_shared_current",
- "android_vendor.VER_arm64_armv8-a_shared",
- "android_vendor.VER_arm_armv7-a-neon_shared_1",
- "android_vendor.VER_arm_armv7-a-neon_shared_2",
- "android_vendor.VER_arm_armv7-a-neon_shared_current",
- "android_vendor.VER_arm_armv7-a-neon_shared",
+ "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",
}
checkEquals(t, "variants for llndk stubs", expected, actual)
- params := ctx.ModuleForTests("libllndk", "android_vendor.VER_arm_armv7-a-neon_shared").Description("generate stub")
+ params := ctx.ModuleForTests("libllndk", "android_vendor.29_arm_armv7-a-neon_shared").Description("generate stub")
checkEquals(t, "use VNDK version for default stubs", "current", params.Args["apiLevel"])
- params = ctx.ModuleForTests("libllndk", "android_vendor.VER_arm_armv7-a-neon_shared_1").Description("generate stub")
+ params = ctx.ModuleForTests("libllndk", "android_vendor.29_arm_armv7-a-neon_shared_1").Description("generate stub")
checkEquals(t, "override apiLevel for versioned stubs", "1", params.Args["apiLevel"])
}
@@ -2714,7 +2828,7 @@
`)
// _static variant is used since _shared reuses *.o from the static variant
- cc := ctx.ModuleForTests("libvendor", "android_vendor.VER_arm_armv7-a-neon_static").Rule("cc")
+ cc := ctx.ModuleForTests("libvendor", "android_vendor.29_arm_armv7-a-neon_static").Rule("cc")
cflags := cc.Args["cFlags"]
if !strings.Contains(cflags, "-Imy_include") {
t.Errorf("cflags for libvendor must contain -Imy_include, but was %#v.", cflags)
@@ -2835,7 +2949,7 @@
// runtime_libs for vendor variants have '.vendor' suffixes if the modules have both core
// and vendor variants.
- variant = "android_vendor.VER_arm64_armv8-a_shared"
+ variant = "android_vendor.29_arm64_armv8-a_shared"
module = ctx.ModuleForTests("libvendor_available1", variant).Module().(*Module)
checkRuntimeLibs(t, []string{"liball_available.vendor"}, module)
@@ -2845,7 +2959,7 @@
// runtime_libs for product variants have '.product' suffixes if the modules have both core
// and product variants.
- variant = "android_product.VER_arm64_armv8-a_shared"
+ variant = "android_product.29_arm64_armv8-a_shared"
module = ctx.ModuleForTests("libproduct_available1", variant).Module().(*Module)
checkRuntimeLibs(t, []string{"liball_available.product"}, module)
@@ -2861,7 +2975,7 @@
module := ctx.ModuleForTests("libvendor_available2", variant).Module().(*Module)
checkRuntimeLibs(t, []string{"liball_available"}, module)
- variant = "android_vendor.VER_arm64_armv8-a_shared"
+ variant = "android_vendor.29_arm64_armv8-a_shared"
module = ctx.ModuleForTests("libvendor_available2", variant).Module().(*Module)
checkRuntimeLibs(t, nil, module)
}
@@ -2912,13 +3026,13 @@
// Check the shared version of lib2.
variant := "android_arm64_armv8-a_shared"
module := ctx.ModuleForTests("lib2", variant).Module().(*Module)
- checkStaticLibs(t, []string{"lib1", "libc++demangle", "libclang_rt.builtins-aarch64-android", "libatomic"}, module)
+ checkStaticLibs(t, []string{"lib1", "libc++demangle", "libclang_rt.builtins-aarch64-android"}, module)
// Check the static version of lib2.
variant = "android_arm64_armv8-a_static"
module = ctx.ModuleForTests("lib2", variant).Module().(*Module)
// libc++_static is linked additionally.
- checkStaticLibs(t, []string{"lib1", "libc++_static", "libc++demangle", "libclang_rt.builtins-aarch64-android", "libatomic"}, module)
+ checkStaticLibs(t, []string{"lib1", "libc++_static", "libc++demangle", "libclang_rt.builtins-aarch64-android"}, module)
}
var compilerFlagsTestCases = []struct {
@@ -3044,7 +3158,7 @@
`)
coreVariant := "android_arm64_armv8-a_shared"
- vendorVariant := "android_vendor.VER_arm64_armv8-a_shared"
+ vendorVariant := "android_vendor.29_arm64_armv8-a_shared"
// test if header search paths are correctly added
// _static variant is used since _shared reuses *.o from the static variant
@@ -3124,7 +3238,7 @@
config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
- config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("29")
config.TestProductVariables.VndkUseCoreVariant = BoolPtr(true)
ctx := testCcWithConfig(t, config)
@@ -3368,6 +3482,9 @@
shared: {
srcs: ["baz.c"],
},
+ bazel_module: {
+ bp2build_available: true,
+ },
}
cc_library_static {
@@ -3804,8 +3921,9 @@
}),
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
variables.MemtagHeapExcludePaths = []string{"subdir_exclude"}
- variables.MemtagHeapSyncIncludePaths = []string{"subdir_sync"}
- variables.MemtagHeapAsyncIncludePaths = []string{"subdir_async"}
+ // "subdir_exclude" is covered by both include and exclude paths. Exclude wins.
+ variables.MemtagHeapSyncIncludePaths = []string{"subdir_sync", "subdir_exclude"}
+ variables.MemtagHeapAsyncIncludePaths = []string{"subdir_async", "subdir_exclude"}
}),
)
diff --git a/cc/gen.go b/cc/gen.go
index 83c019c..b152e02 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -111,9 +111,7 @@
return ret
}
-func genAidl(ctx android.ModuleContext, rule *android.RuleBuilder, aidlFile android.Path,
- outFile, depFile android.ModuleGenPath, aidlFlags string) android.Paths {
-
+func genAidl(ctx android.ModuleContext, rule *android.RuleBuilder, aidlFile android.Path, aidlFlags string) (cppFile android.OutputPath, headerFiles android.Paths) {
aidlPackage := strings.TrimSuffix(aidlFile.Rel(), aidlFile.Base())
baseName := strings.TrimSuffix(aidlFile.Base(), aidlFile.Ext())
shortName := baseName
@@ -126,6 +124,8 @@
}
outDir := android.PathForModuleGen(ctx, "aidl")
+ cppFile = outDir.Join(ctx, aidlPackage, baseName+".cpp")
+ depFile := outDir.Join(ctx, aidlPackage, baseName+".cpp.d")
headerI := outDir.Join(ctx, aidlPackage, baseName+".h")
headerBn := outDir.Join(ctx, aidlPackage, "Bn"+shortName+".h")
headerBp := outDir.Join(ctx, aidlPackage, "Bp"+shortName+".h")
@@ -142,14 +142,14 @@
Flag(aidlFlags).
Input(aidlFile).
OutputDir().
- Output(outFile).
+ Output(cppFile).
ImplicitOutputs(android.WritablePaths{
headerI,
headerBn,
headerBp,
})
- return android.Paths{
+ return cppFile, android.Paths{
headerI,
headerBn,
headerBp,
@@ -293,10 +293,9 @@
aidlRule = android.NewRuleBuilder(pctx, ctx).Sbox(android.PathForModuleGen(ctx, "aidl"),
android.PathForModuleGen(ctx, "aidl.sbox.textproto"))
}
- cppFile := android.GenPathWithExt(ctx, "aidl", srcFile, "cpp")
- depFile := android.GenPathWithExt(ctx, "aidl", srcFile, "cpp.d")
+ cppFile, aidlHeaders := genAidl(ctx, aidlRule, srcFile, buildFlags.aidlFlags)
srcFiles[i] = cppFile
- aidlHeaders := genAidl(ctx, aidlRule, srcFile, cppFile, depFile, buildFlags.aidlFlags)
+
info.aidlHeaders = append(info.aidlHeaders, aidlHeaders...)
// Use the generated headers as order only deps to ensure that they are up to date when
// needed.
diff --git a/cc/genrule.go b/cc/genrule.go
index ca4fda7..82d7205 100644
--- a/cc/genrule.go
+++ b/cc/genrule.go
@@ -75,6 +75,10 @@
return Bool(g.Vendor_ramdisk_available)
}
+func (g *GenruleExtraProperties) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+ return false
+}
+
func (g *GenruleExtraProperties) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
// If the build is using a snapshot, the recovery variant under AOSP directories
// is not needed.
diff --git a/cc/image.go b/cc/image.go
index afe6a0e..bf662c6 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -49,21 +49,15 @@
)
func (ctx *moduleContext) ProductSpecific() bool {
- // Additionally check if this module is inProduct() that means it is a "product" variant of a
- // module. As well as product specific modules, product variants must be installed to /product.
- return ctx.ModuleContext.ProductSpecific() || ctx.mod.InProduct()
+ return ctx.ModuleContext.ProductSpecific() || ctx.mod.productSpecificModuleContext()
}
func (ctx *moduleContext) SocSpecific() bool {
- // Additionally check if this module is inVendor() that means it is a "vendor" variant of a
- // module. As well as SoC specific modules, vendor variants must be installed to /vendor
- // unless they have "odm_available: true".
- return ctx.ModuleContext.SocSpecific() || (ctx.mod.InVendor() && !ctx.mod.VendorVariantToOdm())
+ return ctx.ModuleContext.SocSpecific() || ctx.mod.socSpecificModuleContext()
}
func (ctx *moduleContext) DeviceSpecific() bool {
- // Some vendor variants want to be installed to /odm by setting "odm_available: true".
- return ctx.ModuleContext.DeviceSpecific() || (ctx.mod.InVendor() && ctx.mod.VendorVariantToOdm())
+ return ctx.ModuleContext.DeviceSpecific() || ctx.mod.deviceSpecificModuleContext()
}
func (ctx *moduleContextImpl) inProduct() bool {
@@ -86,6 +80,24 @@
return ctx.mod.InRecovery()
}
+func (c *Module) productSpecificModuleContext() bool {
+ // Additionally check if this module is inProduct() that means it is a "product" variant of a
+ // module. As well as product specific modules, product variants must be installed to /product.
+ return c.InProduct()
+}
+
+func (c *Module) socSpecificModuleContext() bool {
+ // Additionally check if this module is inVendor() that means it is a "vendor" variant of a
+ // module. As well as SoC specific modules, vendor variants must be installed to /vendor
+ // unless they have "odm_available: true".
+ return c.HasVendorVariant() && c.InVendor() && !c.VendorVariantToOdm()
+}
+
+func (c *Module) deviceSpecificModuleContext() bool {
+ // Some vendor variants want to be installed to /odm by setting "odm_available: true".
+ return c.InVendor() && c.VendorVariantToOdm()
+}
+
// Returns true when this module is configured to have core and vendor variants.
func (c *Module) HasVendorVariant() bool {
return Bool(c.VendorProperties.Vendor_available) || Bool(c.VendorProperties.Odm_available)
@@ -187,40 +199,73 @@
return true
}
+// ImageMutatableModule provides a common image mutation interface for LinkableInterface modules.
+type ImageMutatableModule interface {
+ android.Module
+ LinkableInterface
+
+ // AndroidModuleBase returns the android.ModuleBase for this module
+ AndroidModuleBase() *android.ModuleBase
+
+ // VendorAvailable returns true if this module is available on the vendor image.
+ VendorAvailable() bool
+
+ // OdmAvailable returns true if this module is available on the odm image.
+ OdmAvailable() bool
+
+ // ProductAvailable returns true if this module is available on the product image.
+ ProductAvailable() bool
+
+ // RamdiskAvailable returns true if this module is available on the ramdisk image.
+ RamdiskAvailable() bool
+
+ // RecoveryAvailable returns true if this module is available on the recovery image.
+ RecoveryAvailable() bool
+
+ // VendorRamdiskAvailable returns true if this module is available on the vendor ramdisk image.
+ VendorRamdiskAvailable() bool
+
+ // IsSnapshotPrebuilt returns true if this module is a snapshot prebuilt.
+ IsSnapshotPrebuilt() bool
+
+ // SnapshotVersion returns the snapshot version for this module.
+ SnapshotVersion(mctx android.BaseModuleContext) string
+
+ // SdkVersion returns the SDK version for this module.
+ SdkVersion() string
+
+ // ExtraVariants returns the list of extra variants this module requires.
+ ExtraVariants() []string
+
+ // AppendExtraVariant returns an extra variant to the list of extra variants this module requires.
+ AppendExtraVariant(extraVariant string)
+
+ // SetRamdiskVariantNeeded sets whether the Ramdisk Variant is needed.
+ SetRamdiskVariantNeeded(b bool)
+
+ // SetVendorRamdiskVariantNeeded sets whether the Vendor Ramdisk Variant is needed.
+ SetVendorRamdiskVariantNeeded(b bool)
+
+ // SetRecoveryVariantNeeded sets whether the Recovery Variant is needed.
+ SetRecoveryVariantNeeded(b bool)
+
+ // SetCoreVariantNeeded sets whether the Core Variant is needed.
+ SetCoreVariantNeeded(b bool)
+}
+
+var _ ImageMutatableModule = (*Module)(nil)
+
func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) {
- // Validation check
+ m.CheckVndkProperties(mctx)
+ MutateImage(mctx, m)
+}
+
+// CheckVndkProperties checks whether the VNDK-related properties are set correctly.
+// If properties are not set correctly, results in a module context property error.
+func (m *Module) CheckVndkProperties(mctx android.BaseModuleContext) {
vendorSpecific := mctx.SocSpecific() || mctx.DeviceSpecific()
productSpecific := mctx.ProductSpecific()
- if Bool(m.VendorProperties.Vendor_available) {
- if vendorSpecific {
- mctx.PropertyErrorf("vendor_available",
- "doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific: true`")
- }
- if Bool(m.VendorProperties.Odm_available) {
- mctx.PropertyErrorf("vendor_available",
- "doesn't make sense at the same time as `odm_available: true`")
- }
- }
-
- if Bool(m.VendorProperties.Odm_available) {
- if vendorSpecific {
- mctx.PropertyErrorf("odm_available",
- "doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific: true`")
- }
- }
-
- if Bool(m.VendorProperties.Product_available) {
- if productSpecific {
- mctx.PropertyErrorf("product_available",
- "doesn't make sense at the same time as `product_specific: true`")
- }
- if vendorSpecific {
- mctx.PropertyErrorf("product_available",
- "cannot provide product variant from a vendor module. Please use `product_specific: true` with `vendor_available: true`")
- }
- }
-
if vndkdep := m.vndkdep; vndkdep != nil {
if vndkdep.isVndk() {
if vendorSpecific || productSpecific {
@@ -265,6 +310,111 @@
}
}
}
+}
+
+func (m *Module) VendorAvailable() bool {
+ return Bool(m.VendorProperties.Vendor_available)
+}
+
+func (m *Module) OdmAvailable() bool {
+ return Bool(m.VendorProperties.Odm_available)
+}
+
+func (m *Module) ProductAvailable() bool {
+ return Bool(m.VendorProperties.Product_available)
+}
+
+func (m *Module) RamdiskAvailable() bool {
+ return Bool(m.Properties.Ramdisk_available)
+}
+
+func (m *Module) VendorRamdiskAvailable() bool {
+ return Bool(m.Properties.Vendor_ramdisk_available)
+}
+
+func (m *Module) AndroidModuleBase() *android.ModuleBase {
+ return &m.ModuleBase
+}
+
+func (m *Module) RecoveryAvailable() bool {
+ return Bool(m.Properties.Recovery_available)
+}
+
+func (m *Module) ExtraVariants() []string {
+ return m.Properties.ExtraVariants
+}
+
+func (m *Module) AppendExtraVariant(extraVariant string) {
+ m.Properties.ExtraVariants = append(m.Properties.ExtraVariants, extraVariant)
+}
+
+func (m *Module) SetRamdiskVariantNeeded(b bool) {
+ m.Properties.RamdiskVariantNeeded = b
+}
+
+func (m *Module) SetVendorRamdiskVariantNeeded(b bool) {
+ m.Properties.VendorRamdiskVariantNeeded = b
+}
+
+func (m *Module) SetRecoveryVariantNeeded(b bool) {
+ m.Properties.RecoveryVariantNeeded = b
+}
+
+func (m *Module) SetCoreVariantNeeded(b bool) {
+ m.Properties.CoreVariantNeeded = b
+}
+
+func (m *Module) SnapshotVersion(mctx android.BaseModuleContext) string {
+ if snapshot, ok := m.linker.(snapshotInterface); ok {
+ return snapshot.version()
+ } else {
+ mctx.ModuleErrorf("version is unknown for snapshot prebuilt")
+ // Should we be panicking here instead?
+ return ""
+ }
+}
+
+func (m *Module) KernelHeadersDecorator() bool {
+ if _, ok := m.linker.(*kernelHeadersDecorator); ok {
+ return true
+ }
+ return false
+}
+
+// MutateImage handles common image mutations for ImageMutatableModule interfaces.
+func MutateImage(mctx android.BaseModuleContext, m ImageMutatableModule) {
+ // Validation check
+ vendorSpecific := mctx.SocSpecific() || mctx.DeviceSpecific()
+ productSpecific := mctx.ProductSpecific()
+
+ if m.VendorAvailable() {
+ if vendorSpecific {
+ mctx.PropertyErrorf("vendor_available",
+ "doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific: true`")
+ }
+ if m.OdmAvailable() {
+ mctx.PropertyErrorf("vendor_available",
+ "doesn't make sense at the same time as `odm_available: true`")
+ }
+ }
+
+ if m.OdmAvailable() {
+ if vendorSpecific {
+ mctx.PropertyErrorf("odm_available",
+ "doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific: true`")
+ }
+ }
+
+ if m.ProductAvailable() {
+ if productSpecific {
+ mctx.PropertyErrorf("product_available",
+ "doesn't make sense at the same time as `product_specific: true`")
+ }
+ if vendorSpecific {
+ mctx.PropertyErrorf("product_available",
+ "cannot provide product variant from a vendor module. Please use `product_specific: true` with `vendor_available: true`")
+ }
+ }
var coreVariantNeeded bool = false
var ramdiskVariantNeeded bool = false
@@ -287,18 +437,13 @@
productVndkVersion = platformVndkVersion
}
- _, isLLNDKLibrary := m.linker.(*llndkStubDecorator)
- _, isLLNDKHeaders := m.linker.(*llndkHeadersDecorator)
- lib := moduleLibraryInterface(m)
- hasLLNDKStubs := lib != nil && lib.hasLLNDKStubs()
-
- if isLLNDKLibrary || isLLNDKHeaders || hasLLNDKStubs {
+ if m.IsLlndkLibrary() || m.IsLlndkHeaders() || m.HasLlndkStubs() {
// This is an LLNDK library. The implementation of the library will be on /system,
// and vendor and product variants will be created with LLNDK stubs.
// The LLNDK libraries need vendor variants even if there is no VNDK.
// The obsolete llndk_library and llndk_headers modules also need the vendor variants
// so the cc_library LLNDK stubs can depend on them.
- if hasLLNDKStubs {
+ if m.HasLlndkStubs() {
coreVariantNeeded = true
}
if platformVndkVersion != "" {
@@ -315,17 +460,13 @@
// If the device isn't compiling against the VNDK, we always
// use the core mode.
coreVariantNeeded = true
- } else if m.isSnapshotPrebuilt() {
+ } else if m.IsSnapshotPrebuilt() {
// Make vendor variants only for the versions in BOARD_VNDK_VERSION and
// PRODUCT_EXTRA_VNDK_VERSIONS.
- if snapshot, ok := m.linker.(snapshotInterface); ok {
- if m.InstallInRecovery() {
- recoveryVariantNeeded = true
- } else {
- vendorVariants = append(vendorVariants, snapshot.version())
- }
+ if m.InstallInRecovery() {
+ recoveryVariantNeeded = true
} else {
- mctx.ModuleErrorf("version is unknown for snapshot prebuilt")
+ vendorVariants = append(vendorVariants, m.SnapshotVersion(mctx))
}
} else if m.HasNonSystemVariants() && !m.IsVndkExt() {
// This will be available to /system unless it is product_specific
@@ -351,7 +492,7 @@
productVariants = append(productVariants, productVndkVersion)
}
}
- } else if vendorSpecific && String(m.Properties.Sdk_version) == "" {
+ } else if vendorSpecific && m.SdkVersion() == "" {
// This will be available in /vendor (or /odm) only
// kernel_headers is a special module type whose exported headers
@@ -360,7 +501,7 @@
// For other modules, we assume that modules under proprietary
// paths are compatible for BOARD_VNDK_VERSION. The other modules
// are regarded as AOSP, which is PLATFORM_VNDK_VERSION.
- if _, ok := m.linker.(*kernelHeadersDecorator); ok {
+ if m.KernelHeadersDecorator() {
vendorVariants = append(vendorVariants,
platformVndkVersion,
boardVndkVersion,
@@ -378,7 +519,7 @@
}
if boardVndkVersion != "" && productVndkVersion != "" {
- if coreVariantNeeded && productSpecific && String(m.Properties.Sdk_version) == "" {
+ if coreVariantNeeded && productSpecific && m.SdkVersion() == "" {
// The module has "product_specific: true" that does not create core variant.
coreVariantNeeded = false
productVariants = append(productVariants, productVndkVersion)
@@ -390,60 +531,60 @@
productVariants = []string{}
}
- if Bool(m.Properties.Ramdisk_available) {
+ if m.RamdiskAvailable() {
ramdiskVariantNeeded = true
}
- if m.ModuleBase.InstallInRamdisk() {
+ if m.AndroidModuleBase().InstallInRamdisk() {
ramdiskVariantNeeded = true
coreVariantNeeded = false
}
- if Bool(m.Properties.Vendor_ramdisk_available) {
+ if m.VendorRamdiskAvailable() {
vendorRamdiskVariantNeeded = true
}
- if m.ModuleBase.InstallInVendorRamdisk() {
+ if m.AndroidModuleBase().InstallInVendorRamdisk() {
vendorRamdiskVariantNeeded = true
coreVariantNeeded = false
}
- if Bool(m.Properties.Recovery_available) {
+ if m.RecoveryAvailable() {
recoveryVariantNeeded = true
}
- if m.ModuleBase.InstallInRecovery() {
+ if m.AndroidModuleBase().InstallInRecovery() {
recoveryVariantNeeded = true
coreVariantNeeded = false
}
// If using a snapshot, the recovery variant under AOSP directories is not needed,
// except for kernel headers, which needs all variants.
- if _, ok := m.linker.(*kernelHeadersDecorator); !ok &&
- !m.isSnapshotPrebuilt() &&
+ if m.KernelHeadersDecorator() &&
+ !m.IsSnapshotPrebuilt() &&
usingRecoverySnapshot &&
!isRecoveryProprietaryModule(mctx) {
recoveryVariantNeeded = false
}
for _, variant := range android.FirstUniqueStrings(vendorVariants) {
- m.Properties.ExtraVariants = append(m.Properties.ExtraVariants, VendorVariationPrefix+variant)
+ m.AppendExtraVariant(VendorVariationPrefix + variant)
}
for _, variant := range android.FirstUniqueStrings(productVariants) {
- m.Properties.ExtraVariants = append(m.Properties.ExtraVariants, ProductVariationPrefix+variant)
+ m.AppendExtraVariant(ProductVariationPrefix + variant)
}
- m.Properties.RamdiskVariantNeeded = ramdiskVariantNeeded
- m.Properties.VendorRamdiskVariantNeeded = vendorRamdiskVariantNeeded
- m.Properties.RecoveryVariantNeeded = recoveryVariantNeeded
- m.Properties.CoreVariantNeeded = coreVariantNeeded
+ m.SetRamdiskVariantNeeded(ramdiskVariantNeeded)
+ m.SetVendorRamdiskVariantNeeded(vendorRamdiskVariantNeeded)
+ m.SetRecoveryVariantNeeded(recoveryVariantNeeded)
+ m.SetCoreVariantNeeded(coreVariantNeeded)
// Disable the module if no variants are needed.
if !ramdiskVariantNeeded &&
!recoveryVariantNeeded &&
!coreVariantNeeded &&
- len(m.Properties.ExtraVariants) == 0 {
+ len(m.ExtraVariants()) == 0 {
m.Disable()
}
}
@@ -460,6 +601,10 @@
return c.Properties.VendorRamdiskVariantNeeded
}
+func (c *Module) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+ return false
+}
+
func (c *Module) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
return c.Properties.RecoveryVariantNeeded
}
diff --git a/cc/library.go b/cc/library.go
index 091acfe..53be3a5 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -206,6 +206,7 @@
RegisterLibraryBuildComponents(android.InitRegistrationContext)
android.RegisterBp2BuildMutator("cc_library_static", CcLibraryStaticBp2Build)
+ android.RegisterBp2BuildMutator("cc_library", CcLibraryBp2Build)
}
func RegisterLibraryBuildComponents(ctx android.RegistrationContext) {
@@ -216,6 +217,67 @@
ctx.RegisterModuleType("cc_library_host_shared", LibraryHostSharedFactory)
}
+// For bp2build conversion.
+type bazelCcLibraryAttributes struct {
+ Srcs bazel.LabelListAttribute
+ Hdrs bazel.LabelListAttribute
+ Copts bazel.StringListAttribute
+ Linkopts bazel.StringListAttribute
+ Deps bazel.LabelListAttribute
+ User_link_flags bazel.StringListAttribute
+ Includes bazel.StringListAttribute
+}
+
+type bazelCcLibrary struct {
+ android.BazelTargetModuleBase
+ bazelCcLibraryAttributes
+}
+
+func (m *bazelCcLibrary) Name() string {
+ return m.BaseModuleName()
+}
+
+func (m *bazelCcLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {}
+
+func BazelCcLibraryFactory() android.Module {
+ module := &bazelCcLibrary{}
+ module.AddProperties(&module.bazelCcLibraryAttributes)
+ android.InitBazelTargetModule(module)
+ return module
+}
+
+func CcLibraryBp2Build(ctx android.TopDownMutatorContext) {
+ m, ok := ctx.Module().(*Module)
+ if !ok || !m.ConvertWithBp2build(ctx) {
+ return
+ }
+
+ if ctx.ModuleType() != "cc_library" {
+ return
+ }
+
+ compilerAttrs := bp2BuildParseCompilerProps(ctx, m)
+ linkerAttrs := bp2BuildParseLinkerProps(ctx, m)
+ exportedIncludes, exportedIncludesHeaders := bp2BuildParseExportedIncludes(ctx, m)
+ compilerAttrs.hdrs.Append(exportedIncludesHeaders)
+
+ attrs := &bazelCcLibraryAttributes{
+ Srcs: compilerAttrs.srcs,
+ Hdrs: compilerAttrs.hdrs,
+ Copts: compilerAttrs.copts,
+ Linkopts: linkerAttrs.linkopts,
+ Deps: linkerAttrs.deps,
+ Includes: exportedIncludes,
+ }
+
+ props := bazel.BazelTargetModuleProperties{
+ Rule_class: "cc_library",
+ Bzl_load_location: "//build/bazel/rules:full_cc_library.bzl",
+ }
+
+ ctx.CreateBazelTargetModule(BazelCcLibraryFactory, m.Name(), props, attrs)
+}
+
// cc_library creates both static and/or shared libraries for a device and/or
// host. By default, a cc_library has a single variant that targets the device.
// Specifying `host_supported: true` also creates a library that targets the
@@ -421,15 +483,24 @@
func (handler *staticLibraryBazelHandler) generateBazelBuildActions(ctx android.ModuleContext, label string) bool {
bazelCtx := ctx.Config().BazelContext
- outputPaths, objPaths, ok := bazelCtx.GetOutputFilesAndCcObjectFiles(label, ctx.Arch().ArchType)
+ ccInfo, ok, err := bazelCtx.GetCcInfo(label, ctx.Arch().ArchType)
+ if err != nil {
+ ctx.ModuleErrorf("Error getting Bazel CcInfo: %s", err)
+ return false
+ }
if !ok {
return ok
}
- if len(outputPaths) != 1 {
+ outputPaths := ccInfo.OutputFiles
+ objPaths := ccInfo.CcObjectFiles
+ if len(outputPaths) > 1 {
// TODO(cparsons): This is actually expected behavior for static libraries with no srcs.
// We should support this.
- ctx.ModuleErrorf("expected exactly one output file for '%s', but got %s", label, objPaths)
+ ctx.ModuleErrorf("expected at most one output file for '%s', but got %s", label, objPaths)
return false
+ } else if len(outputPaths) == 0 {
+ handler.module.outputFile = android.OptionalPath{}
+ return true
}
outputFilePath := android.PathForBazelOut(ctx, outputPaths[0])
handler.module.outputFile = android.OptionalPathForPath(outputFilePath)
@@ -453,7 +524,15 @@
Direct(outputFilePath).
Build(),
})
- handler.module.outputFile = android.OptionalPathForPath(android.PathForBazelOut(ctx, objPaths[0]))
+ if i, ok := handler.module.linker.(snapshotLibraryInterface); ok {
+ // Dependencies on this library will expect collectedSnapshotHeaders to
+ // be set, otherwise validation will fail. For now, set this to an empty
+ // list.
+ // TODO(cparsons): More closely mirror the collectHeadersForSnapshot
+ // implementation.
+ i.(*libraryDecorator).collectedSnapshotHeaders = android.Paths{}
+ }
+
return ok
}
@@ -2046,44 +2125,13 @@
return outputFile
}
-func Bp2BuildParseHeaderLibs(ctx android.TopDownMutatorContext, module *Module) bazel.LabelListAttribute {
- var headerLibs []string
- for _, linkerProps := range module.linker.linkerProps() {
- if baseLinkerProps, ok := linkerProps.(*BaseLinkerProperties); ok {
- headerLibs = baseLinkerProps.Header_libs
- // FIXME: re-export include dirs from baseLinkerProps.Export_header_lib_headers?
- break
- }
- }
- headerLibsLabels := bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, headerLibs))
- return headerLibsLabels
-}
-
-func Bp2BuildParseExportedIncludes(ctx android.TopDownMutatorContext, module *Module) (bazel.LabelListAttribute, bazel.LabelListAttribute) {
- libraryDecorator := module.linker.(*libraryDecorator)
-
- includeDirs := libraryDecorator.flagExporter.Properties.Export_system_include_dirs
- includeDirs = append(includeDirs, libraryDecorator.flagExporter.Properties.Export_include_dirs...)
-
- includeDirsLabels := android.BazelLabelForModuleSrc(ctx, includeDirs)
-
- var includeDirGlobs []string
- for _, includeDir := range includeDirs {
- includeDirGlobs = append(includeDirGlobs, includeDir+"/**/*.h")
- includeDirGlobs = append(includeDirGlobs, includeDir+"/**/*.inc")
- includeDirGlobs = append(includeDirGlobs, includeDir+"/**/*.hpp")
- }
-
- headersLabels := android.BazelLabelForModuleSrc(ctx, includeDirGlobs)
- return bazel.MakeLabelListAttribute(includeDirsLabels), bazel.MakeLabelListAttribute(headersLabels)
-}
-
type bazelCcLibraryStaticAttributes struct {
- Copts []string
+ Copts bazel.StringListAttribute
Srcs bazel.LabelListAttribute
Deps bazel.LabelListAttribute
+ Linkopts bazel.StringListAttribute
Linkstatic bool
- Includes bazel.LabelListAttribute
+ Includes bazel.StringListAttribute
Hdrs bazel.LabelListAttribute
}
@@ -2112,24 +2160,37 @@
return
}
- var copts []string
- var srcs []string
+ compilerAttrs := bp2BuildParseCompilerProps(ctx, module)
+
var includeDirs []string
var localIncludeDirs []string
for _, props := range module.compiler.compilerProps() {
if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
- copts = baseCompilerProps.Cflags
- srcs = baseCompilerProps.Srcs
- includeDirs = baseCompilerProps.Include_dirs
- localIncludeDirs = baseCompilerProps.Local_include_dirs
+ // TODO: these should be arch and os specific.
+ includeDirs = bp2BuildMakePathsRelativeToModule(ctx, baseCompilerProps.Include_dirs)
+ localIncludeDirs = bp2BuildMakePathsRelativeToModule(ctx, baseCompilerProps.Local_include_dirs)
break
}
}
- srcsLabels := bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, srcs))
+
+ // Soong implicitly includes headers from the module's directory.
+ // For Bazel builds to work we have to make these header includes explicit.
+ if module.compiler.(*libraryDecorator).includeBuildDirectory() {
+ localIncludeDirs = append(localIncludeDirs, ".")
+ }
+
+ // For Bazel, be more explicit about headers - list all header files in include dirs as srcs
+ for _, includeDir := range includeDirs {
+ compilerAttrs.srcs.Value.Append(bp2BuildListHeadersInDir(ctx, includeDir))
+ }
+ for _, localIncludeDir := range localIncludeDirs {
+ compilerAttrs.srcs.Value.Append(bp2BuildListHeadersInDir(ctx, localIncludeDir))
+ }
var staticLibs []string
var wholeStaticLibs []string
for _, props := range module.linker.linkerProps() {
+ // TODO: move this into bp2buildParseLinkerProps
if baseLinkerProperties, ok := props.(*BaseLinkerProperties); ok {
staticLibs = baseLinkerProperties.Static_libs
wholeStaticLibs = baseLinkerProperties.Whole_static_libs
@@ -2143,25 +2204,26 @@
depsLabels := android.BazelLabelForModuleDeps(ctx, allDeps)
+ exportedIncludes, exportedIncludesHeaders := bp2BuildParseExportedIncludes(ctx, module)
+
// FIXME: Unify absolute vs relative paths
// FIXME: Use -I copts instead of setting includes= ?
- allIncludes := includeDirs
- allIncludes = append(allIncludes, localIncludeDirs...)
- includesLabels := android.BazelLabelForModuleSrc(ctx, allIncludes)
+ allIncludes := exportedIncludes
+ allIncludes.Value = append(allIncludes.Value, includeDirs...)
+ allIncludes.Value = append(allIncludes.Value, localIncludeDirs...)
- exportedIncludesLabels, exportedIncludesHeadersLabels := Bp2BuildParseExportedIncludes(ctx, module)
- includesLabels.Append(exportedIncludesLabels.Value)
+ compilerAttrs.hdrs.Append(exportedIncludesHeaders)
- headerLibsLabels := Bp2BuildParseHeaderLibs(ctx, module)
- depsLabels.Append(headerLibsLabels.Value)
+ linkerAttrs := bp2BuildParseLinkerProps(ctx, module)
+ depsLabels.Append(linkerAttrs.deps.Value)
attrs := &bazelCcLibraryStaticAttributes{
- Copts: copts,
- Srcs: srcsLabels,
+ Copts: compilerAttrs.copts,
+ Srcs: compilerAttrs.srcs,
Deps: bazel.MakeLabelListAttribute(depsLabels),
Linkstatic: true,
- Includes: bazel.MakeLabelListAttribute(includesLabels),
- Hdrs: exportedIncludesHeadersLabels,
+ Includes: allIncludes,
+ Hdrs: compilerAttrs.hdrs,
}
props := bazel.BazelTargetModuleProperties{
diff --git a/cc/library_headers.go b/cc/library_headers.go
index 8286848..076ce80 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -62,8 +62,9 @@
}
type bazelCcLibraryHeadersAttributes struct {
+ Copts bazel.StringListAttribute
Hdrs bazel.LabelListAttribute
- Includes bazel.LabelListAttribute
+ Includes bazel.StringListAttribute
Deps bazel.LabelListAttribute
}
@@ -94,14 +95,15 @@
return
}
- exportedIncludesLabels, exportedIncludesHeadersLabels := Bp2BuildParseExportedIncludes(ctx, module)
-
- headerLibsLabels := Bp2BuildParseHeaderLibs(ctx, module)
+ exportedIncludes, exportedIncludesHeaders := bp2BuildParseExportedIncludes(ctx, module)
+ compilerAttrs := bp2BuildParseCompilerProps(ctx, module)
+ linkerAttrs := bp2BuildParseLinkerProps(ctx, module)
attrs := &bazelCcLibraryHeadersAttributes{
- Includes: exportedIncludesLabels,
- Hdrs: exportedIncludesHeadersLabels,
- Deps: headerLibsLabels,
+ Copts: compilerAttrs.copts,
+ Includes: exportedIncludes,
+ Hdrs: exportedIncludesHeaders,
+ Deps: linkerAttrs.deps,
}
props := bazel.BazelTargetModuleProperties{
diff --git a/cc/linkable.go b/cc/linkable.go
index 6aa238b..571a3bb 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -98,10 +98,24 @@
InVendor() bool
UseSdk() bool
+
+ // IsLlndk returns true for both LLNDK (public) and LLNDK-private libs.
+ IsLlndk() bool
+
+ // IsLlndkPublic returns true only for LLNDK (public) libs.
+ IsLlndkPublic() bool
+
+ // IsLlndkHeaders returns true if this module is an LLNDK headers module.
+ IsLlndkHeaders() bool
+
+ // IsLlndkLibrary returns true if this module is an LLNDK library module.
+ IsLlndkLibrary() bool
+
+ // HasLlndkStubs returns true if this module has LLNDK stubs.
+ HasLlndkStubs() bool
+
UseVndk() bool
MustUseVendorVariant() bool
- IsLlndk() bool
- IsLlndkPublic() bool
IsVndk() bool
IsVndkExt() bool
IsVndkPrivate() bool
@@ -110,6 +124,9 @@
HasNonSystemVariants() bool
InProduct() bool
+ // SubName returns the modules SubName, used for image and NDK/SDK variations.
+ SubName() string
+
SdkVersion() string
MinSdkVersion() string
AlwaysSdk() bool
@@ -121,6 +138,10 @@
SetPreventInstall()
// SetHideFromMake sets the HideFromMake property to 'true' for this module.
SetHideFromMake()
+
+ // 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
}
var (
@@ -152,6 +173,15 @@
}
}
+// DepTagMakeSuffix returns the makeSuffix value of a particular library dependency tag.
+// Returns an empty string if not a library dependency tag.
+func DepTagMakeSuffix(depTag blueprint.DependencyTag) string {
+ if libDepTag, ok := depTag.(libraryDependencyTag); ok {
+ return libDepTag.makeSuffix
+ }
+ return ""
+}
+
// SharedDepTag returns the dependency tag for any C++ shared libraries.
func SharedDepTag() blueprint.DependencyTag {
return libraryDependencyTag{Kind: sharedLibraryDependency}
diff --git a/cc/linker.go b/cc/linker.go
index 21281d2..ae33356 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -321,10 +321,9 @@
}
if ctx.toolchain().Bionic() {
- // libclang_rt.builtins and libatomic have to be last on the command line
+ // libclang_rt.builtins has to be last on the command line
if !Bool(linker.Properties.No_libcrt) {
deps.LateStaticLibs = append(deps.LateStaticLibs, config.BuiltinsRuntimeLibrary(ctx.toolchain()))
- deps.LateStaticLibs = append(deps.LateStaticLibs, "libatomic")
}
deps.SystemSharedLibs = linker.Properties.System_shared_libs
diff --git a/cc/ndk_headers.go b/cc/ndk_headers.go
index 60f931d..56fd5fc 100644
--- a/cc/ndk_headers.go
+++ b/cc/ndk_headers.go
@@ -75,11 +75,6 @@
// Path to the NOTICE file associated with the headers.
License *string `android:"path"`
-
- // True if this API is not yet ready to be shipped in the NDK. It will be
- // available in the platform for testing, but will be excluded from the
- // sysroot provided to the NDK proper.
- Draft bool
}
type headerModule struct {
@@ -184,11 +179,6 @@
// Path to the NOTICE file associated with the headers.
License *string
-
- // True if this API is not yet ready to be shipped in the NDK. It will be
- // available in the platform for testing, but will be excluded from the
- // sysroot provided to the NDK proper.
- Draft bool
}
// Like ndk_headers, but preprocesses the headers with the bionic versioner:
@@ -311,11 +301,6 @@
// Path to the NOTICE file associated with the headers.
License *string
-
- // True if this API is not yet ready to be shipped in the NDK. It will be
- // available in the platform for testing, but will be excluded from the
- // sysroot provided to the NDK proper.
- Draft bool
}
type preprocessedHeadersModule struct {
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 10de889..95d8477 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -20,6 +20,7 @@
"sync"
"github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
"android/soong/android"
)
@@ -78,11 +79,6 @@
// used. This is only needed to work around platform bugs like
// https://github.com/android-ndk/ndk/issues/265.
Unversioned_until *string
-
- // True if this API is not yet ready to be shipped in the NDK. It will be
- // available in the platform for testing, but will be excluded from the
- // sysroot provided to the NDK proper.
- Draft bool
}
type stubDecorator struct {
@@ -147,8 +143,8 @@
return false
}
- this.unversionedUntil, err = nativeApiLevelFromUserWithDefault(ctx,
- String(this.properties.Unversioned_until), "minimum")
+ str := proptools.StringDefault(this.properties.Unversioned_until, "minimum")
+ this.unversionedUntil, err = nativeApiLevelFromUser(ctx, str)
if err != nil {
ctx.PropertyErrorf("unversioned_until", err.Error())
return false
diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go
index 70b15c1..d8c500e 100644
--- a/cc/ndk_sysroot.go
+++ b/cc/ndk_sysroot.go
@@ -104,38 +104,22 @@
}
if m, ok := module.(*headerModule); ok {
- if ctx.Config().ExcludeDraftNdkApis() && m.properties.Draft {
- return
- }
-
installPaths = append(installPaths, m.installPaths...)
licensePaths = append(licensePaths, m.licensePath)
}
if m, ok := module.(*versionedHeaderModule); ok {
- if ctx.Config().ExcludeDraftNdkApis() && m.properties.Draft {
- return
- }
-
installPaths = append(installPaths, m.installPaths...)
licensePaths = append(licensePaths, m.licensePath)
}
if m, ok := module.(*preprocessedHeadersModule); ok {
- if ctx.Config().ExcludeDraftNdkApis() && m.properties.Draft {
- return
- }
-
installPaths = append(installPaths, m.installPaths...)
licensePaths = append(licensePaths, m.licensePath)
}
if m, ok := module.(*Module); ok {
if installer, ok := m.installer.(*stubDecorator); ok && m.library.buildStubs() {
- if ctx.Config().ExcludeDraftNdkApis() &&
- installer.properties.Draft {
- return
- }
installPaths = append(installPaths, installer.installPath)
}
diff --git a/cc/object.go b/cc/object.go
index ea8d7d3..9bb279a 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -113,6 +113,7 @@
// For bp2build conversion.
type bazelObjectAttributes struct {
Srcs bazel.LabelListAttribute
+ Hdrs bazel.LabelListAttribute
Deps bazel.LabelListAttribute
Copts bazel.StringListAttribute
Asflags []string
@@ -156,18 +157,11 @@
}
// Set arch-specific configurable attributes
- var copts bazel.StringListAttribute
- var srcs bazel.LabelListAttribute
+ compilerAttrs := bp2BuildParseCompilerProps(ctx, m)
var localIncludeDirs []string
var asFlags []string
for _, props := range m.compiler.compilerProps() {
if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
- copts.Value = baseCompilerProps.Cflags
- srcs = bazel.MakeLabelListAttribute(
- android.BazelLabelForModuleSrcExcludes(
- ctx,
- baseCompilerProps.Srcs,
- baseCompilerProps.Exclude_srcs))
localIncludeDirs = baseCompilerProps.Local_include_dirs
break
}
@@ -202,17 +196,11 @@
}
// TODO(b/183595872) warn/error if we're not handling product variables
- for arch, p := range m.GetArchProperties(&BaseCompilerProperties{}) {
- if cProps, ok := p.(*BaseCompilerProperties); ok {
- srcs.SetValueForArch(arch.Name, android.BazelLabelForModuleSrcExcludes(ctx, cProps.Srcs, cProps.Exclude_srcs))
- copts.SetValueForArch(arch.Name, cProps.Cflags)
- }
- }
-
attrs := &bazelObjectAttributes{
- Srcs: srcs,
+ Srcs: compilerAttrs.srcs,
+ Hdrs: compilerAttrs.hdrs,
Deps: deps,
- Copts: copts,
+ Copts: compilerAttrs.copts,
Asflags: asFlags,
Local_include_dirs: localIncludeDirs,
}
diff --git a/cc/object_test.go b/cc/object_test.go
index 6ff8a00..f82d544 100644
--- a/cc/object_test.go
+++ b/cc/object_test.go
@@ -15,6 +15,7 @@
package cc
import (
+ "android/soong/android"
"testing"
)
@@ -27,5 +28,28 @@
linker_script: "foo.lds",
}`)
})
+}
+func TestCcObjectWithBazel(t *testing.T) {
+ bp := `
+cc_object {
+ name: "foo",
+ srcs: ["baz.o"],
+ bazel_module: { label: "//foo/bar:bar" },
+}`
+ config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
+ config.BazelContext = android.MockBazelContext{
+ OutputBaseDir: "outputbase",
+ LabelToOutputFiles: map[string][]string{
+ "//foo/bar:bar": []string{"bazel_out.o"}}}
+ ctx := testCcWithConfig(t, config)
+
+ module := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon").Module()
+ outputFiles, err := module.(android.OutputFileProducer).OutputFiles("")
+ if err != nil {
+ t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
+ }
+
+ expectedOutputFiles := []string{"outputbase/execroot/__main__/bazel_out.o"}
+ android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
}
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 6b9a3d5..c19b1ff 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -305,6 +305,7 @@
func NewPrebuiltStaticLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) {
module, library := NewPrebuiltLibrary(hod)
library.BuildOnlyStatic()
+ module.bazelHandler = &prebuiltStaticLibraryBazelHandler{module: module, library: library}
return module, library
}
@@ -319,6 +320,56 @@
properties prebuiltObjectProperties
}
+type prebuiltStaticLibraryBazelHandler struct {
+ bazelHandler
+
+ module *Module
+ library *libraryDecorator
+}
+
+func (h *prebuiltStaticLibraryBazelHandler) generateBazelBuildActions(ctx android.ModuleContext, label string) bool {
+ bazelCtx := ctx.Config().BazelContext
+ ccInfo, ok, err := bazelCtx.GetCcInfo(label, ctx.Arch().ArchType)
+ if err != nil {
+ ctx.ModuleErrorf("Error getting Bazel CcInfo: %s", err)
+ }
+ if !ok {
+ return false
+ }
+ staticLibs := ccInfo.CcStaticLibraryFiles
+ if len(staticLibs) > 1 {
+ ctx.ModuleErrorf("expected 1 static library from bazel target %q, got %s", label, staticLibs)
+ return false
+ }
+
+ // TODO(b/184543518): cc_prebuilt_library_static may have properties for re-exporting flags
+
+ // TODO(eakammer):Add stub-related flags if this library is a stub library.
+ // h.library.exportVersioningMacroIfNeeded(ctx)
+
+ // Dependencies on this library will expect collectedSnapshotHeaders to be set, otherwise
+ // validation will fail. For now, set this to an empty list.
+ // TODO(cparsons): More closely mirror the collectHeadersForSnapshot implementation.
+ h.library.collectedSnapshotHeaders = android.Paths{}
+
+ if len(staticLibs) == 0 {
+ h.module.outputFile = android.OptionalPath{}
+ return true
+ }
+
+ out := android.PathForBazelOut(ctx, staticLibs[0])
+ h.module.outputFile = android.OptionalPathForPath(out)
+
+ depSet := android.NewDepSetBuilder(android.TOPOLOGICAL).Direct(out).Build()
+ ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
+ StaticLibrary: out,
+
+ TransitiveStaticLibrariesForOrdering: depSet,
+ })
+
+ return true
+}
+
func (p *prebuiltObjectLinker) prebuilt() *android.Prebuilt {
return &p.Prebuilt
}
diff --git a/cc/sabi.go b/cc/sabi.go
index 4a1ba3c..c0eb57c 100644
--- a/cc/sabi.go
+++ b/cc/sabi.go
@@ -141,7 +141,7 @@
}
// Don't create ABI dump for prebuilts.
- if m.Prebuilt() != nil || m.isSnapshotPrebuilt() {
+ if m.Prebuilt() != nil || m.IsSnapshotPrebuilt() {
return false
}
diff --git a/cc/sanitize.go b/cc/sanitize.go
index e1ac9f0..397121e 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -83,7 +83,7 @@
const (
Asan SanitizerType = iota + 1
- hwasan
+ Hwasan
tsan
intOverflow
cfi
@@ -97,7 +97,7 @@
switch t {
case Asan:
return "asan"
- case hwasan:
+ case Hwasan:
return "hwasan"
case tsan:
return "tsan"
@@ -121,7 +121,7 @@
switch t {
case Asan:
return "address"
- case hwasan:
+ case Hwasan:
return "hwaddress"
case memtag_heap:
return "memtag_heap"
@@ -144,7 +144,7 @@
switch t {
case Asan:
return true
- case hwasan:
+ case Hwasan:
return true
case tsan:
return true
@@ -163,7 +163,7 @@
// incompatibleWithCfi returns true if a sanitizer is incompatible with CFI.
func (t SanitizerType) incompatibleWithCfi() bool {
- return t == Asan || t == Fuzzer || t == hwasan
+ return t == Asan || t == Fuzzer || t == Hwasan
}
type SanitizeUserProps struct {
@@ -745,7 +745,7 @@
switch t {
case Asan:
return sanitize.Properties.Sanitize.Address
- case hwasan:
+ case Hwasan:
return sanitize.Properties.Sanitize.Hwaddress
case tsan:
return sanitize.Properties.Sanitize.Thread
@@ -767,7 +767,7 @@
// isUnsanitizedVariant returns true if no sanitizers are enabled.
func (sanitize *sanitize) isUnsanitizedVariant() bool {
return !sanitize.isSanitizerEnabled(Asan) &&
- !sanitize.isSanitizerEnabled(hwasan) &&
+ !sanitize.isSanitizerEnabled(Hwasan) &&
!sanitize.isSanitizerEnabled(tsan) &&
!sanitize.isSanitizerEnabled(cfi) &&
!sanitize.isSanitizerEnabled(scs) &&
@@ -778,7 +778,7 @@
// isVariantOnProductionDevice returns true if variant is for production devices (no non-production sanitizers enabled).
func (sanitize *sanitize) isVariantOnProductionDevice() bool {
return !sanitize.isSanitizerEnabled(Asan) &&
- !sanitize.isSanitizerEnabled(hwasan) &&
+ !sanitize.isSanitizerEnabled(Hwasan) &&
!sanitize.isSanitizerEnabled(tsan) &&
!sanitize.isSanitizerEnabled(Fuzzer)
}
@@ -787,7 +787,7 @@
switch t {
case Asan:
sanitize.Properties.Sanitize.Address = boolPtr(b)
- case hwasan:
+ case Hwasan:
sanitize.Properties.Sanitize.Hwaddress = boolPtr(b)
case tsan:
sanitize.Properties.Sanitize.Thread = boolPtr(b)
@@ -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 {
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.
@@ -1080,6 +1080,12 @@
if Bool(c.sanitize.Properties.Sanitize.Diag.Memtag_heap) {
noteDep = "note_memtag_heap_sync"
}
+ // If we're using snapshots, redirect to snapshot whenever possible
+ // TODO(b/178470649): clean manual snapshot redirections
+ snapshot := mctx.Provider(SnapshotInfoProvider).(SnapshotInfo)
+ if lib, ok := snapshot.StaticLibs[noteDep]; ok {
+ noteDep = lib
+ }
depTag := libraryDependencyTag{Kind: staticLibraryDependency, wholeStatic: true}
variations := append(mctx.Target().Variations(),
blueprint.Variation{Mutator: "link", Variation: "static"})
@@ -1280,7 +1286,7 @@
// For cfi/scs/hwasan, we can export both sanitized and un-sanitized variants
// to Make, because the sanitized version has a different suffix in name.
// For other types of sanitizers, suppress the variation that is disabled.
- if t != cfi && t != scs && t != hwasan {
+ if t != cfi && t != scs && t != Hwasan {
if isSanitizerEnabled {
modules[0].(PlatformSanitizeable).SetPreventInstall()
modules[0].(PlatformSanitizeable).SetHideFromMake()
@@ -1294,7 +1300,7 @@
if c.StaticallyLinked() && c.ExportedToMake() {
if t == cfi {
cfiStaticLibs(mctx.Config()).add(c, c.Module().Name())
- } else if t == hwasan {
+ } else if t == Hwasan {
hwasanStaticLibs(mctx.Config()).add(c, c.Module().Name())
}
}
@@ -1411,7 +1417,7 @@
func hwasanStaticLibs(config android.Config) *sanitizerStaticLibsMap {
return config.Once(hwasanStaticLibsKey, func() interface{} {
- return newSanitizerStaticLibsMap(hwasan)
+ return newSanitizerStaticLibsMap(Hwasan)
}).(*sanitizerStaticLibsMap)
}
diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go
index bbb8896..6d48aed 100644
--- a/cc/snapshot_prebuilt.go
+++ b/cc/snapshot_prebuilt.go
@@ -308,6 +308,10 @@
return false
}
+func (s *snapshot) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+ return false
+}
+
func (s *snapshot) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
return false
}
@@ -337,7 +341,8 @@
for _, name := range names {
snapshotMap[name] = name +
getSnapshotNameSuffix(snapshotSuffix+moduleSuffix,
- s.baseSnapshot.version(), ctx.Arch().ArchType.Name)
+ s.baseSnapshot.version(),
+ ctx.DeviceConfig().Arches()[0].ArchType.String())
}
return snapshotMap
}
@@ -396,7 +401,7 @@
Target_arch string
// Suffix to be added to the module name when exporting to Android.mk, e.g. ".vendor".
- Androidmk_suffix string
+ Androidmk_suffix string `blueprint:"mutated"`
// Suffix to be added to the module name, e.g., vendor_shared,
// recovery_shared, etc.
@@ -417,6 +422,7 @@
// will be seen as "libbase.vendor_static.30.arm64" by Soong.
type baseSnapshotDecorator struct {
baseProperties baseSnapshotDecoratorProperties
+ image snapshotImage
}
func (p *baseSnapshotDecorator) Name(name string) string {
@@ -447,10 +453,21 @@
return p.baseProperties.Androidmk_suffix
}
+func (p *baseSnapshotDecorator) setSnapshotAndroidMkSuffix(ctx android.ModuleContext) {
+ if ctx.OtherModuleDependencyVariantExists([]blueprint.Variation{
+ {Mutator: "image", Variation: android.CoreVariation},
+ }, ctx.Module().(*Module).BaseModuleName()) {
+ p.baseProperties.Androidmk_suffix = p.image.moduleNameSuffix()
+ } else {
+ p.baseProperties.Androidmk_suffix = ""
+ }
+}
+
// Call this with a module suffix after creating a snapshot module, such as
// vendorSnapshotSharedSuffix, recoverySnapshotBinarySuffix, etc.
-func (p *baseSnapshotDecorator) init(m *Module, snapshotSuffix, moduleSuffix string) {
- p.baseProperties.ModuleSuffix = snapshotSuffix + moduleSuffix
+func (p *baseSnapshotDecorator) init(m *Module, image snapshotImage, moduleSuffix string) {
+ p.image = image
+ p.baseProperties.ModuleSuffix = image.moduleNameSuffix() + moduleSuffix
m.AddProperties(&p.baseProperties)
android.AddLoadHook(m, func(ctx android.LoadHookContext) {
vendorSnapshotLoadHook(ctx, p)
@@ -532,6 +549,8 @@
// As snapshots are prebuilts, this just returns the prebuilt binary after doing things which are
// done by normal library decorator, e.g. exporting flags.
func (p *snapshotLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path {
+ p.setSnapshotAndroidMkSuffix(ctx)
+
if p.header() {
return p.libraryDecorator.link(ctx, flags, deps, objs)
}
@@ -544,10 +563,18 @@
return nil
}
+ // Flags specified directly to this module.
p.libraryDecorator.reexportDirs(android.PathsForModuleSrc(ctx, p.properties.Export_include_dirs)...)
p.libraryDecorator.reexportSystemDirs(android.PathsForModuleSrc(ctx, p.properties.Export_system_include_dirs)...)
p.libraryDecorator.reexportFlags(p.properties.Export_flags...)
+ // Flags reexported from dependencies. (e.g. vndk_prebuilt_shared)
+ p.libraryDecorator.reexportDirs(deps.ReexportedDirs...)
+ p.libraryDecorator.reexportSystemDirs(deps.ReexportedSystemDirs...)
+ p.libraryDecorator.reexportFlags(deps.ReexportedFlags...)
+ p.libraryDecorator.reexportDeps(deps.ReexportedDeps...)
+ p.libraryDecorator.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...)
+
in := android.PathForModuleSrc(ctx, *p.properties.Src)
p.unstrippedOutputFile = in
@@ -614,7 +641,7 @@
}
}
-func snapshotLibraryFactory(snapshotSuffix, moduleSuffix string) (*Module, *snapshotLibraryDecorator) {
+func snapshotLibraryFactory(image snapshotImage, moduleSuffix string) (*Module, *snapshotLibraryDecorator) {
module, library := NewLibrary(android.DeviceSupported)
module.stl = nil
@@ -637,7 +664,7 @@
module.linker = prebuilt
module.installer = prebuilt
- prebuilt.init(module, snapshotSuffix, moduleSuffix)
+ prebuilt.init(module, image, moduleSuffix)
module.AddProperties(
&prebuilt.properties,
&prebuilt.sanitizerProperties,
@@ -651,7 +678,7 @@
// overrides the vendor variant of the cc shared library with the same name, if BOARD_VNDK_VERSION
// is set.
func VendorSnapshotSharedFactory() android.Module {
- module, prebuilt := snapshotLibraryFactory(vendorSnapshotImageSingleton.moduleNameSuffix(), snapshotSharedSuffix)
+ module, prebuilt := snapshotLibraryFactory(vendorSnapshotImageSingleton, snapshotSharedSuffix)
prebuilt.libraryDecorator.BuildOnlyShared()
return module.Init()
}
@@ -661,7 +688,7 @@
// overrides the recovery variant of the cc shared library with the same name, if BOARD_VNDK_VERSION
// is set.
func RecoverySnapshotSharedFactory() android.Module {
- module, prebuilt := snapshotLibraryFactory(recoverySnapshotImageSingleton.moduleNameSuffix(), snapshotSharedSuffix)
+ module, prebuilt := snapshotLibraryFactory(recoverySnapshotImageSingleton, snapshotSharedSuffix)
prebuilt.libraryDecorator.BuildOnlyShared()
return module.Init()
}
@@ -671,7 +698,7 @@
// overrides the vendor variant of the cc static library with the same name, if BOARD_VNDK_VERSION
// is set.
func VendorSnapshotStaticFactory() android.Module {
- module, prebuilt := snapshotLibraryFactory(vendorSnapshotImageSingleton.moduleNameSuffix(), snapshotStaticSuffix)
+ module, prebuilt := snapshotLibraryFactory(vendorSnapshotImageSingleton, snapshotStaticSuffix)
prebuilt.libraryDecorator.BuildOnlyStatic()
return module.Init()
}
@@ -681,7 +708,7 @@
// overrides the recovery variant of the cc static library with the same name, if BOARD_VNDK_VERSION
// is set.
func RecoverySnapshotStaticFactory() android.Module {
- module, prebuilt := snapshotLibraryFactory(recoverySnapshotImageSingleton.moduleNameSuffix(), snapshotStaticSuffix)
+ module, prebuilt := snapshotLibraryFactory(recoverySnapshotImageSingleton, snapshotStaticSuffix)
prebuilt.libraryDecorator.BuildOnlyStatic()
return module.Init()
}
@@ -691,7 +718,7 @@
// overrides the vendor variant of the cc header library with the same name, if BOARD_VNDK_VERSION
// is set.
func VendorSnapshotHeaderFactory() android.Module {
- module, prebuilt := snapshotLibraryFactory(vendorSnapshotImageSingleton.moduleNameSuffix(), snapshotHeaderSuffix)
+ module, prebuilt := snapshotLibraryFactory(vendorSnapshotImageSingleton, snapshotHeaderSuffix)
prebuilt.libraryDecorator.HeaderOnly()
return module.Init()
}
@@ -701,7 +728,7 @@
// overrides the recovery variant of the cc header library with the same name, if BOARD_VNDK_VERSION
// is set.
func RecoverySnapshotHeaderFactory() android.Module {
- module, prebuilt := snapshotLibraryFactory(recoverySnapshotImageSingleton.moduleNameSuffix(), snapshotHeaderSuffix)
+ module, prebuilt := snapshotLibraryFactory(recoverySnapshotImageSingleton, snapshotHeaderSuffix)
prebuilt.libraryDecorator.HeaderOnly()
return module.Init()
}
@@ -739,6 +766,8 @@
// cc modules' link functions are to link compiled objects into final binaries.
// As snapshots are prebuilts, this just returns the prebuilt binary
func (p *snapshotBinaryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path {
+ p.setSnapshotAndroidMkSuffix(ctx)
+
if !p.matchesWithDevice(ctx.DeviceConfig()) {
return nil
}
@@ -767,17 +796,17 @@
// development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_binary
// overrides the vendor variant of the cc binary with the same name, if BOARD_VNDK_VERSION is set.
func VendorSnapshotBinaryFactory() android.Module {
- return snapshotBinaryFactory(vendorSnapshotImageSingleton.moduleNameSuffix(), snapshotBinarySuffix)
+ return snapshotBinaryFactory(vendorSnapshotImageSingleton, snapshotBinarySuffix)
}
// recovery_snapshot_binary is a special prebuilt executable binary which is auto-generated by
// development/vendor_snapshot/update.py. As a part of recovery snapshot, recovery_snapshot_binary
// overrides the recovery variant of the cc binary with the same name, if BOARD_VNDK_VERSION is set.
func RecoverySnapshotBinaryFactory() android.Module {
- return snapshotBinaryFactory(recoverySnapshotImageSingleton.moduleNameSuffix(), snapshotBinarySuffix)
+ return snapshotBinaryFactory(recoverySnapshotImageSingleton, snapshotBinarySuffix)
}
-func snapshotBinaryFactory(snapshotSuffix, moduleSuffix string) android.Module {
+func snapshotBinaryFactory(image snapshotImage, moduleSuffix string) android.Module {
module, binary := NewBinary(android.DeviceSupported)
binary.baseLinker.Properties.No_libcrt = BoolPtr(true)
binary.baseLinker.Properties.Nocrt = BoolPtr(true)
@@ -796,7 +825,7 @@
module.stl = nil
module.linker = prebuilt
- prebuilt.init(module, snapshotSuffix, moduleSuffix)
+ prebuilt.init(module, image, moduleSuffix)
module.AddProperties(&prebuilt.properties)
return module.Init()
}
@@ -832,6 +861,8 @@
// cc modules' link functions are to link compiled objects into final binaries.
// As snapshots are prebuilts, this just returns the prebuilt binary
func (p *snapshotObjectLinker) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path {
+ p.setSnapshotAndroidMkSuffix(ctx)
+
if !p.matchesWithDevice(ctx.DeviceConfig()) {
return nil
}
@@ -856,7 +887,7 @@
}
module.linker = prebuilt
- prebuilt.init(module, vendorSnapshotImageSingleton.moduleNameSuffix(), snapshotObjectSuffix)
+ prebuilt.init(module, vendorSnapshotImageSingleton, snapshotObjectSuffix)
module.AddProperties(&prebuilt.properties)
return module.Init()
}
@@ -874,7 +905,7 @@
}
module.linker = prebuilt
- prebuilt.init(module, recoverySnapshotImageSingleton.moduleNameSuffix(), snapshotObjectSuffix)
+ prebuilt.init(module, recoverySnapshotImageSingleton, snapshotObjectSuffix)
module.AddProperties(&prebuilt.properties)
return module.Init()
}
diff --git a/cc/stl.go b/cc/stl.go
index 594231d..4f8865f 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -140,6 +140,17 @@
}
func staticUnwinder(ctx android.BaseModuleContext) string {
+ vndkVersion := ctx.Module().(*Module).VndkVersion()
+
+ // Modules using R vndk use different unwinder
+ if vndkVersion == "30" {
+ if ctx.Arch().ArchType == android.Arm {
+ return "libunwind_llvm"
+ } else {
+ return "libgcc_stripped"
+ }
+ }
+
return "libunwind"
}
diff --git a/cc/testing.go b/cc/testing.go
index 6e35655..ff32bff 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -63,17 +63,6 @@
func commonDefaultModules() string {
return `
toolchain_library {
- name: "libatomic",
- defaults: ["linux_bionic_supported"],
- vendor_available: true,
- vendor_ramdisk_available: true,
- product_available: true,
- recovery_available: true,
- native_bridge_supported: true,
- src: "",
- }
-
- toolchain_library {
name: "libcompiler_rt-extras",
vendor_available: true,
vendor_ramdisk_available: true,
@@ -200,29 +189,6 @@
srcs: [""],
}
- toolchain_library {
- name: "libgcc",
- defaults: ["linux_bionic_supported"],
- vendor_available: true,
- product_available: true,
- recovery_available: true,
- src: "",
- apex_available: [
- "//apex_available:platform",
- "//apex_available:anyapex",
- ],
- }
-
- toolchain_library {
- name: "libgcc_stripped",
- defaults: ["linux_bionic_supported"],
- vendor_available: true,
- product_available: true,
- recovery_available: true,
- sdk_version: "current",
- src: "",
- }
-
cc_library {
name: "libc",
defaults: ["linux_bionic_supported"],
@@ -398,16 +364,6 @@
"//apex_available:anyapex",
],
}
- cc_library {
- name: "libunwind_llvm",
- no_libcrt: true,
- nocrt: true,
- system_shared_libs: [],
- stl: "none",
- vendor_available: true,
- product_available: true,
- recovery_available: true,
- }
cc_defaults {
name: "crt_defaults",
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index 4014fe0..2f68cca 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -173,7 +173,7 @@
return false
}
// the module must be installed in target image
- if !apexInfo.IsForPlatform() || m.isSnapshotPrebuilt() || !image.inImage(m)() {
+ if !apexInfo.IsForPlatform() || m.IsSnapshotPrebuilt() || !image.inImage(m)() {
return false
}
// skip kernel_headers which always depend on vendor
@@ -196,7 +196,7 @@
if m.sanitize != nil {
// 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} {
+ for _, t := range []SanitizerType{scs, Hwasan} {
if !l.shared() && m.sanitize.isSanitizerEnabled(t) {
return false
}
@@ -238,7 +238,6 @@
type snapshotJsonFlags struct {
ModuleName string `json:",omitempty"`
RelativeInstallPath string `json:",omitempty"`
- AndroidMkSuffix string `json:",omitempty"`
// library flags
ExportedDirs []string `json:",omitempty"`
@@ -352,7 +351,6 @@
} else {
prop.RelativeInstallPath = m.RelativeInstallPath()
}
- prop.AndroidMkSuffix = m.Properties.SubName
prop.RuntimeLibs = m.Properties.SnapshotRuntimeLibs
prop.Required = m.RequiredModuleNames()
for _, path := range m.InitRc() {
diff --git a/cc/vendor_snapshot_test.go b/cc/vendor_snapshot_test.go
index 8d13ceb..66396f7 100644
--- a/cc/vendor_snapshot_test.go
+++ b/cc/vendor_snapshot_test.go
@@ -88,7 +88,7 @@
`
config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
- config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("29")
ctx := testCcWithConfig(t, config)
// Check Vendor snapshot output.
@@ -108,7 +108,7 @@
archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
// For shared libraries, only non-VNDK vendor_available modules are captured
- sharedVariant := fmt.Sprintf("android_vendor.VER_%s_%s_shared", archType, archVariant)
+ sharedVariant := fmt.Sprintf("android_vendor.29_%s_%s_shared", archType, archVariant)
sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
checkSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.so", sharedDir, sharedVariant)
checkSnapshot(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.so", sharedDir, sharedVariant)
@@ -121,8 +121,8 @@
// For static libraries, all vendor:true and vendor_available modules (including VNDK) are captured.
// Also cfi variants are captured, except for prebuilts like toolchain_library
- staticVariant := fmt.Sprintf("android_vendor.VER_%s_%s_static", archType, archVariant)
- staticCfiVariant := fmt.Sprintf("android_vendor.VER_%s_%s_static_cfi", archType, archVariant)
+ staticVariant := fmt.Sprintf("android_vendor.29_%s_%s_static", archType, archVariant)
+ staticCfiVariant := fmt.Sprintf("android_vendor.29_%s_%s_static_cfi", archType, archVariant)
staticDir := filepath.Join(snapshotVariantPath, archDir, "static")
checkSnapshot(t, ctx, snapshotSingleton, "libb", "libb.a", staticDir, staticVariant)
checkSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.a", staticDir, staticVariant)
@@ -142,7 +142,7 @@
// For binary executables, all vendor:true and vendor_available modules are captured.
if archType == "arm64" {
- binaryVariant := fmt.Sprintf("android_vendor.VER_%s_%s", archType, archVariant)
+ binaryVariant := fmt.Sprintf("android_vendor.29_%s_%s", archType, archVariant)
binaryDir := filepath.Join(snapshotVariantPath, archDir, "binary")
checkSnapshot(t, ctx, snapshotSingleton, "vendor_bin", "vendor_bin", binaryDir, binaryVariant)
checkSnapshot(t, ctx, snapshotSingleton, "vendor_available_bin", "vendor_available_bin", binaryDir, binaryVariant)
@@ -156,7 +156,7 @@
jsonFiles = append(jsonFiles, filepath.Join(headerDir, "libvendor_headers.json"))
// For object modules, all vendor:true and vendor_available modules are captured.
- objectVariant := fmt.Sprintf("android_vendor.VER_%s_%s", archType, archVariant)
+ objectVariant := fmt.Sprintf("android_vendor.29_%s_%s", archType, archVariant)
objectDir := filepath.Join(snapshotVariantPath, archDir, "object")
checkSnapshot(t, ctx, snapshotSingleton, "obj", "obj.o", objectDir, objectVariant)
jsonFiles = append(jsonFiles, filepath.Join(objectDir, "obj.o.json"))
@@ -214,7 +214,7 @@
`
config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
- config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("29")
config.TestProductVariables.DirectedVendorSnapshot = true
config.TestProductVariables.VendorSnapshotModules = make(map[string]bool)
config.TestProductVariables.VendorSnapshotModules["libvendor"] = true
@@ -237,7 +237,7 @@
archVariant := arch[1]
archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
- sharedVariant := fmt.Sprintf("android_vendor.VER_%s_%s_shared", archType, archVariant)
+ sharedVariant := fmt.Sprintf("android_vendor.29_%s_%s_shared", archType, archVariant)
sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
// Included modules
@@ -271,7 +271,6 @@
enabled: true,
},
nocrt: true,
- compile_multilib: "64",
}
cc_library {
@@ -281,7 +280,6 @@
no_libcrt: true,
stl: "none",
system_shared_libs: [],
- compile_multilib: "64",
}
cc_library {
@@ -291,6 +289,25 @@
no_libcrt: true,
stl: "none",
system_shared_libs: [],
+ }
+
+ cc_library {
+ name: "lib32",
+ vendor: true,
+ nocrt: true,
+ no_libcrt: true,
+ stl: "none",
+ system_shared_libs: [],
+ compile_multilib: "32",
+ }
+
+ cc_library {
+ name: "lib64",
+ vendor: true,
+ nocrt: true,
+ no_libcrt: true,
+ stl: "none",
+ system_shared_libs: [],
compile_multilib: "64",
}
@@ -301,14 +318,23 @@
no_libcrt: true,
stl: "none",
system_shared_libs: [],
- compile_multilib: "64",
+ }
+
+ cc_binary {
+ name: "bin32",
+ vendor: true,
+ nocrt: true,
+ no_libcrt: true,
+ stl: "none",
+ system_shared_libs: [],
+ compile_multilib: "32",
}
`
vndkBp := `
vndk_prebuilt_shared {
name: "libvndk",
- version: "BOARD",
+ version: "30",
target_arch: "arm64",
vendor_available: true,
product_available: true,
@@ -320,13 +346,17 @@
srcs: ["libvndk.so"],
export_include_dirs: ["include/libvndk"],
},
+ arm: {
+ srcs: ["libvndk.so"],
+ export_include_dirs: ["include/libvndk"],
+ },
},
}
// old snapshot module which has to be ignored
vndk_prebuilt_shared {
name: "libvndk",
- version: "OLD",
+ version: "26",
target_arch: "arm64",
vendor_available: true,
product_available: true,
@@ -338,6 +368,28 @@
srcs: ["libvndk.so"],
export_include_dirs: ["include/libvndk"],
},
+ arm: {
+ srcs: ["libvndk.so"],
+ export_include_dirs: ["include/libvndk"],
+ },
+ },
+ }
+
+ // different arch snapshot which has to be ignored
+ vndk_prebuilt_shared {
+ name: "libvndk",
+ version: "30",
+ target_arch: "arm",
+ vendor_available: true,
+ product_available: true,
+ vndk: {
+ enabled: true,
+ },
+ arch: {
+ arm: {
+ srcs: ["libvndk.so"],
+ export_include_dirs: ["include/libvndk"],
+ },
},
}
`
@@ -350,7 +402,6 @@
no_libcrt: true,
stl: "none",
system_shared_libs: [],
- compile_multilib: "64",
}
cc_library_shared {
@@ -362,7 +413,28 @@
system_shared_libs: [],
shared_libs: ["libvndk", "libvendor_available"],
static_libs: ["libvendor", "libvendor_without_snapshot"],
- compile_multilib: "64",
+ arch: {
+ arm64: {
+ shared_libs: ["lib64"],
+ },
+ arm: {
+ shared_libs: ["lib32"],
+ },
+ },
+ srcs: ["client.cpp"],
+ }
+
+ cc_library_shared {
+ name: "libclient_cfi",
+ vendor: true,
+ nocrt: true,
+ no_libcrt: true,
+ stl: "none",
+ system_shared_libs: [],
+ static_libs: ["libvendor"],
+ sanitize: {
+ cfi: true,
+ },
srcs: ["client.cpp"],
}
@@ -371,52 +443,83 @@
vendor: true,
nocrt: true,
no_libcrt: true,
- stl: "none",
+ stl: "libc++_static",
system_shared_libs: [],
static_libs: ["libvndk"],
- compile_multilib: "64",
srcs: ["bin.cpp"],
}
vendor_snapshot {
name: "vendor_snapshot",
- compile_multilib: "first",
- version: "BOARD",
- vndk_libs: [
- "libvndk",
- ],
- static_libs: [
- "libvendor",
- "libvendor_available",
- "libvndk",
- ],
- shared_libs: [
- "libvendor",
- "libvendor_available",
- ],
- binaries: [
- "bin",
- ],
+ version: "30",
+ arch: {
+ arm64: {
+ vndk_libs: [
+ "libvndk",
+ ],
+ static_libs: [
+ "libc++_static",
+ "libc++demangle",
+ "libgcc_stripped",
+ "libvendor",
+ "libvendor_available",
+ "libvndk",
+ "lib64",
+ ],
+ shared_libs: [
+ "libvendor",
+ "libvendor_available",
+ "lib64",
+ ],
+ binaries: [
+ "bin",
+ ],
+ },
+ arm: {
+ vndk_libs: [
+ "libvndk",
+ ],
+ static_libs: [
+ "libvendor",
+ "libvendor_available",
+ "libvndk",
+ "lib32",
+ ],
+ shared_libs: [
+ "libvendor",
+ "libvendor_available",
+ "lib32",
+ ],
+ binaries: [
+ "bin32",
+ ],
+ },
+ }
}
vendor_snapshot_static {
name: "libvndk",
- version: "BOARD",
+ version: "30",
target_arch: "arm64",
+ compile_multilib: "both",
vendor: true,
arch: {
arm64: {
src: "libvndk.a",
- export_include_dirs: ["include/libvndk"],
+ },
+ arm: {
+ src: "libvndk.a",
},
},
+ shared_libs: ["libvndk"],
+ export_shared_lib_headers: ["libvndk"],
}
vendor_snapshot_shared {
name: "libvendor",
- version: "BOARD",
+ version: "30",
target_arch: "arm64",
- compile_multilib: "64",
+ compile_multilib: "both",
vendor: true,
shared_libs: [
"libvendor_without_snapshot",
@@ -428,16 +531,85 @@
src: "libvendor.so",
export_include_dirs: ["include/libvendor"],
},
+ arm: {
+ src: "libvendor.so",
+ export_include_dirs: ["include/libvendor"],
+ },
+ },
+ }
+
+ vendor_snapshot_static {
+ name: "lib32",
+ version: "30",
+ target_arch: "arm64",
+ compile_multilib: "32",
+ vendor: true,
+ arch: {
+ arm: {
+ src: "lib32.a",
+ },
+ },
+ }
+
+ vendor_snapshot_shared {
+ name: "lib32",
+ version: "30",
+ target_arch: "arm64",
+ compile_multilib: "32",
+ vendor: true,
+ arch: {
+ arm: {
+ src: "lib32.so",
+ },
+ },
+ }
+
+ vendor_snapshot_static {
+ name: "lib64",
+ version: "30",
+ target_arch: "arm64",
+ compile_multilib: "64",
+ vendor: true,
+ arch: {
+ arm64: {
+ src: "lib64.a",
+ },
+ },
+ }
+
+ vendor_snapshot_shared {
+ name: "lib64",
+ version: "30",
+ target_arch: "arm64",
+ compile_multilib: "64",
+ vendor: true,
+ arch: {
+ arm64: {
+ src: "lib64.so",
+ },
},
}
vendor_snapshot_static {
name: "libvendor",
- version: "BOARD",
+ version: "30",
target_arch: "arm64",
+ compile_multilib: "both",
vendor: true,
arch: {
arm64: {
+ cfi: {
+ src: "libvendor.cfi.a",
+ export_include_dirs: ["include/libvendor_cfi"],
+ },
+ src: "libvendor.a",
+ export_include_dirs: ["include/libvendor"],
+ },
+ arm: {
+ cfi: {
+ src: "libvendor.cfi.a",
+ export_include_dirs: ["include/libvendor_cfi"],
+ },
src: "libvendor.a",
export_include_dirs: ["include/libvendor"],
},
@@ -446,36 +618,84 @@
vendor_snapshot_shared {
name: "libvendor_available",
- androidmk_suffix: ".vendor",
- version: "BOARD",
+ version: "30",
target_arch: "arm64",
+ compile_multilib: "both",
vendor: true,
arch: {
arm64: {
src: "libvendor_available.so",
export_include_dirs: ["include/libvendor"],
},
+ arm: {
+ src: "libvendor_available.so",
+ export_include_dirs: ["include/libvendor"],
+ },
},
}
vendor_snapshot_static {
name: "libvendor_available",
- androidmk_suffix: ".vendor",
- version: "BOARD",
+ version: "30",
target_arch: "arm64",
+ compile_multilib: "both",
vendor: true,
arch: {
arm64: {
src: "libvendor_available.a",
export_include_dirs: ["include/libvendor"],
},
+ arm: {
+ src: "libvendor_available.so",
+ export_include_dirs: ["include/libvendor"],
+ },
+ },
+ }
+
+ vendor_snapshot_static {
+ name: "libc++_static",
+ version: "30",
+ target_arch: "arm64",
+ compile_multilib: "64",
+ vendor: true,
+ arch: {
+ arm64: {
+ src: "libc++_static.a",
+ },
+ },
+ }
+
+ vendor_snapshot_static {
+ name: "libc++demangle",
+ version: "30",
+ target_arch: "arm64",
+ compile_multilib: "64",
+ vendor: true,
+ arch: {
+ arm64: {
+ src: "libc++demangle.a",
+ },
+ },
+ }
+
+ vendor_snapshot_static {
+ name: "libgcc_stripped",
+ version: "30",
+ target_arch: "arm64",
+ compile_multilib: "64",
+ vendor: true,
+ arch: {
+ arm64: {
+ src: "libgcc_stripped.a",
+ },
},
}
vendor_snapshot_binary {
name: "bin",
- version: "BOARD",
+ version: "30",
target_arch: "arm64",
+ compile_multilib: "64",
vendor: true,
arch: {
arm64: {
@@ -484,11 +704,39 @@
},
}
+ vendor_snapshot_binary {
+ name: "bin32",
+ version: "30",
+ target_arch: "arm64",
+ compile_multilib: "32",
+ vendor: true,
+ arch: {
+ arm: {
+ src: "bin32",
+ },
+ },
+ }
+
// old snapshot module which has to be ignored
vendor_snapshot_binary {
name: "bin",
- version: "OLD",
+ version: "26",
target_arch: "arm64",
+ compile_multilib: "first",
+ vendor: true,
+ arch: {
+ arm64: {
+ src: "bin",
+ },
+ },
+ }
+
+ // different arch snapshot which has to be ignored
+ vendor_snapshot_binary {
+ name: "bin",
+ version: "30",
+ target_arch: "arm",
+ compile_multilib: "first",
vendor: true,
arch: {
arm64: {
@@ -500,25 +748,36 @@
depsBp := GatherRequiredDepsForTest(android.Android)
mockFS := map[string][]byte{
- "deps/Android.bp": []byte(depsBp),
- "framework/Android.bp": []byte(frameworkBp),
- "vendor/Android.bp": []byte(vendorProprietaryBp),
- "vendor/bin": nil,
- "vendor/bin.cpp": nil,
- "vendor/client.cpp": nil,
- "vendor/include/libvndk/a.h": nil,
- "vendor/include/libvendor/b.h": nil,
- "vendor/libvndk.a": nil,
- "vendor/libvendor.a": nil,
- "vendor/libvendor.so": nil,
- "vndk/Android.bp": []byte(vndkBp),
- "vndk/include/libvndk/a.h": nil,
- "vndk/libvndk.so": nil,
+ "deps/Android.bp": []byte(depsBp),
+ "framework/Android.bp": []byte(frameworkBp),
+ "framework/symbol.txt": nil,
+ "vendor/Android.bp": []byte(vendorProprietaryBp),
+ "vendor/bin": nil,
+ "vendor/bin32": nil,
+ "vendor/bin.cpp": nil,
+ "vendor/client.cpp": nil,
+ "vendor/include/libvndk/a.h": nil,
+ "vendor/include/libvendor/b.h": nil,
+ "vendor/include/libvendor_cfi/c.h": nil,
+ "vendor/libc++_static.a": nil,
+ "vendor/libc++demangle.a": nil,
+ "vendor/libgcc_striped.a": nil,
+ "vendor/libvndk.a": nil,
+ "vendor/libvendor.a": nil,
+ "vendor/libvendor.cfi.a": nil,
+ "vendor/libvendor.so": nil,
+ "vendor/lib32.a": nil,
+ "vendor/lib32.so": nil,
+ "vendor/lib64.a": nil,
+ "vendor/lib64.so": nil,
+ "vndk/Android.bp": []byte(vndkBp),
+ "vndk/include/libvndk/a.h": nil,
+ "vndk/libvndk.so": nil,
}
config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS)
- config.TestProductVariables.DeviceVndkVersion = StringPtr("BOARD")
- config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+ config.TestProductVariables.DeviceVndkVersion = StringPtr("30")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("31")
ctx := CreateTestContext(config)
ctx.Register()
@@ -527,11 +786,17 @@
_, errs = ctx.PrepareBuildActions(config)
android.FailIfErrored(t, errs)
- sharedVariant := "android_vendor.BOARD_arm64_armv8-a_shared"
- staticVariant := "android_vendor.BOARD_arm64_armv8-a_static"
- binaryVariant := "android_vendor.BOARD_arm64_armv8-a"
+ sharedVariant := "android_vendor.30_arm64_armv8-a_shared"
+ staticVariant := "android_vendor.30_arm64_armv8-a_static"
+ binaryVariant := "android_vendor.30_arm64_armv8-a"
- // libclient uses libvndk.vndk.BOARD.arm64, libvendor.vendor_static.BOARD.arm64, libvendor_without_snapshot
+ sharedCfiVariant := "android_vendor.30_arm64_armv8-a_shared_cfi"
+ staticCfiVariant := "android_vendor.30_arm64_armv8-a_static_cfi"
+
+ shared32Variant := "android_vendor.30_arm_armv7-a-neon_shared"
+ binary32Variant := "android_vendor.30_arm_armv7-a-neon"
+
+ // libclient uses libvndk.vndk.30.arm64, libvendor.vendor_static.30.arm64, libvendor_without_snapshot
libclientCcFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("cc").Args["cFlags"]
for _, includeFlags := range []string{
"-Ivndk/include/libvndk", // libvndk
@@ -545,8 +810,8 @@
libclientLdFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("ld").Args["libFlags"]
for _, input := range [][]string{
- []string{sharedVariant, "libvndk.vndk.BOARD.arm64"},
- []string{staticVariant, "libvendor.vendor_static.BOARD.arm64"},
+ []string{sharedVariant, "libvndk.vndk.30.arm64"},
+ []string{staticVariant, "libvendor.vendor_static.30.arm64"},
[]string{staticVariant, "libvendor_without_snapshot"},
} {
outputPaths := getOutputPaths(ctx, input[0] /* variant */, []string{input[1]} /* module name */)
@@ -556,7 +821,7 @@
}
libclientAndroidMkSharedLibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).Properties.AndroidMkSharedLibs
- if g, w := libclientAndroidMkSharedLibs, []string{"libvndk.vendor", "libvendor_available.vendor"}; !reflect.DeepEqual(g, w) {
+ if g, w := libclientAndroidMkSharedLibs, []string{"libvndk.vendor", "libvendor_available.vendor", "lib64"}; !reflect.DeepEqual(g, w) {
t.Errorf("wanted libclient AndroidMkSharedLibs %q, got %q", w, g)
}
@@ -565,36 +830,63 @@
t.Errorf("wanted libclient AndroidMkStaticLibs %q, got %q", w, g)
}
- // bin_without_snapshot uses libvndk.vendor_static.BOARD.arm64
+ libclient32AndroidMkSharedLibs := ctx.ModuleForTests("libclient", shared32Variant).Module().(*Module).Properties.AndroidMkSharedLibs
+ if g, w := libclient32AndroidMkSharedLibs, []string{"libvndk.vendor", "libvendor_available.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
+ 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.",
+ "-Ivendor/include/libvendor_cfi", libclientCfiCcFlags)
+ }
+
+ libclientCfiLdFlags := ctx.ModuleForTests("libclient_cfi", sharedCfiVariant).Rule("ld").Args["libFlags"]
+ libvendorCfiOutputPaths := getOutputPaths(ctx, staticCfiVariant, []string{"libvendor.vendor_static.30.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)
binWithoutSnapshotCcFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("cc").Args["cFlags"]
- if !strings.Contains(binWithoutSnapshotCcFlags, "-Ivendor/include/libvndk") {
+ if !strings.Contains(binWithoutSnapshotCcFlags, "-Ivndk/include/libvndk") {
t.Errorf("flags for bin_without_snapshot must contain %#v, but was %#v.",
"-Ivendor/include/libvndk", binWithoutSnapshotCcFlags)
}
binWithoutSnapshotLdFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("ld").Args["libFlags"]
- libVndkStaticOutputPaths := getOutputPaths(ctx, staticVariant, []string{"libvndk.vendor_static.BOARD.arm64"})
+ libVndkStaticOutputPaths := getOutputPaths(ctx, staticVariant, []string{"libvndk.vendor_static.30.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.BOARD.arm64
- ctx.ModuleForTests("libvendor.vendor_shared.BOARD.arm64", sharedVariant).Output("libvendor.so")
+ // libvendor.so is installed by libvendor.vendor_shared.30.arm64
+ ctx.ModuleForTests("libvendor.vendor_shared.30.arm64", sharedVariant).Output("libvendor.so")
- // libvendor_available.so is installed by libvendor_available.vendor_shared.BOARD.arm64
- ctx.ModuleForTests("libvendor_available.vendor_shared.BOARD.arm64", sharedVariant).Output("libvendor_available.so")
+ // lib64.so is installed by lib64.vendor_shared.30.arm64
+ ctx.ModuleForTests("lib64.vendor_shared.30.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")
+
+ // 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_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.BOARD.arm64
- ctx.ModuleForTests("bin.vendor_binary.BOARD.arm64", binaryVariant).Output("bin")
+ // bin is installed by bin.vendor_binary.30.arm64
+ ctx.ModuleForTests("bin.vendor_binary.30.arm64", binaryVariant).Output("bin")
+
+ // bin32 is installed by bin32.vendor_binary.30.arm64
+ ctx.ModuleForTests("bin32.vendor_binary.30.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.BOARD variant
+ // libvendor, libvendor_available and bin don't have vendor.30 variant
libvendorVariants := ctx.ModuleVariantsForTests("libvendor")
if inList(sharedVariant, libvendorVariants) {
t.Errorf("libvendor must not have variant %#v, but it does", sharedVariant)
@@ -613,11 +905,23 @@
func TestVendorSnapshotSanitizer(t *testing.T) {
bp := `
+ vendor_snapshot {
+ name: "vendor_snapshot",
+ version: "28",
+ arch: {
+ arm64: {
+ static_libs: [
+ "libsnapshot",
+ "note_memtag_heap_sync",
+ ],
+ },
+ },
+ }
vendor_snapshot_static {
name: "libsnapshot",
vendor: true,
target_arch: "arm64",
- version: "BOARD",
+ version: "28",
arch: {
arm64: {
src: "libsnapshot.a",
@@ -627,20 +931,53 @@
},
},
}
+
+ vendor_snapshot_static {
+ name: "note_memtag_heap_sync",
+ vendor: true,
+ target_arch: "arm64",
+ version: "28",
+ arch: {
+ arm64: {
+ src: "note_memtag_heap_sync.a",
+ },
+ },
+ }
+
+ cc_test {
+ name: "vstest",
+ gtest: false,
+ vendor: true,
+ compile_multilib: "64",
+ nocrt: true,
+ no_libcrt: true,
+ stl: "none",
+ static_libs: ["libsnapshot"],
+ system_shared_libs: [],
+ }
`
- config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
- config.TestProductVariables.DeviceVndkVersion = StringPtr("BOARD")
- config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+
+ mockFS := map[string][]byte{
+ "vendor/Android.bp": []byte(bp),
+ "vendor/libc++demangle.a": nil,
+ "vendor/libsnapshot.a": nil,
+ "vendor/libsnapshot.cfi.a": nil,
+ "vendor/note_memtag_heap_sync.a": nil,
+ }
+
+ config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS)
+ config.TestProductVariables.DeviceVndkVersion = StringPtr("28")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("29")
ctx := testCcWithConfig(t, config)
// Check non-cfi and cfi variant.
- staticVariant := "android_vendor.BOARD_arm64_armv8-a_static"
- staticCfiVariant := "android_vendor.BOARD_arm64_armv8-a_static_cfi"
+ staticVariant := "android_vendor.28_arm64_armv8-a_static"
+ staticCfiVariant := "android_vendor.28_arm64_armv8-a_static_cfi"
- staticModule := ctx.ModuleForTests("libsnapshot.vendor_static.BOARD.arm64", staticVariant).Module().(*Module)
+ staticModule := ctx.ModuleForTests("libsnapshot.vendor_static.28.arm64", staticVariant).Module().(*Module)
assertString(t, staticModule.outputFile.Path().Base(), "libsnapshot.a")
- staticCfiModule := ctx.ModuleForTests("libsnapshot.vendor_static.BOARD.arm64", staticCfiVariant).Module().(*Module)
+ staticCfiModule := ctx.ModuleForTests("libsnapshot.vendor_static.28.arm64", staticCfiVariant).Module().(*Module)
assertString(t, staticCfiModule.outputFile.Path().Base(), "libsnapshot.cfi.a")
}
@@ -709,7 +1046,7 @@
config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS)
config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
- config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("29")
ctx := CreateTestContext(config)
ctx.Register()
@@ -744,7 +1081,7 @@
archVariant := arch[1]
archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
- sharedVariant := fmt.Sprintf("android_vendor.VER_%s_%s_shared", archType, archVariant)
+ sharedVariant := fmt.Sprintf("android_vendor.29_%s_%s_shared", archType, archVariant)
sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
// Included modules
@@ -801,7 +1138,7 @@
config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS)
config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
- config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("29")
ctx := CreateTestContext(config)
ctx.Register()
@@ -875,7 +1212,7 @@
`
config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
config.TestProductVariables.RecoverySnapshotVersion = StringPtr("current")
- config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("29")
ctx := testCcWithConfig(t, config)
// Check Recovery snapshot output.
@@ -993,7 +1330,7 @@
config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS)
config.TestProductVariables.RecoverySnapshotVersion = StringPtr("current")
- config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("29")
ctx := CreateTestContext(config)
ctx.Register()
@@ -1094,7 +1431,7 @@
config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
config.TestProductVariables.RecoverySnapshotVersion = StringPtr("current")
- config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("29")
config.TestProductVariables.DirectedRecoverySnapshot = true
config.TestProductVariables.RecoverySnapshotModules = make(map[string]bool)
config.TestProductVariables.RecoverySnapshotModules["librecovery"] = true
diff --git a/cc/vndk.go b/cc/vndk.go
index b7047e9..1a8a454 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -609,8 +609,8 @@
}
// !inVendor: There's product/vendor variants for VNDK libs. We only care about vendor variants.
// !installable: Snapshot only cares about "installable" modules.
- // isSnapshotPrebuilt: Snapshotting a snapshot doesn't make sense.
- if !m.InVendor() || !m.installable(apexInfo) || m.isSnapshotPrebuilt() {
+ // IsSnapshotPrebuilt: Snapshotting a snapshot doesn't make sense.
+ if !m.InVendor() || !m.installable(apexInfo) || m.IsSnapshotPrebuilt() {
return nil, "", false
}
l, ok := m.linker.(snapshotLibraryInterface)
diff --git a/cmd/pom2bp/pom2bp.go b/cmd/pom2bp/pom2bp.go
index d9116b0..d31489e 100644
--- a/cmd/pom2bp/pom2bp.go
+++ b/cmd/pom2bp/pom2bp.go
@@ -401,6 +401,8 @@
{{- end}}
],
{{- end}}
+ {{- else if not .IsHostOnly}}
+ min_sdk_version: "{{.DefaultMinSdkVersion}}",
{{- end}}
}
`))
@@ -442,6 +444,8 @@
{{- end}}
],
{{- end}}
+ {{- else if not .IsHostOnly}}
+ min_sdk_version: "{{.DefaultMinSdkVersion}}",
{{- end}}
}
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 3abf978..1e796ec 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -23,29 +23,43 @@
"strings"
"time"
+ "android/soong/bp2build"
"android/soong/shared"
"github.com/google/blueprint/bootstrap"
+ "github.com/google/blueprint/deptools"
"android/soong/android"
- "android/soong/bp2build"
)
var (
- topDir string
- outDir string
+ topDir string
+ outDir string
+ availableEnvFile string
+ usedEnvFile string
+
+ delveListen string
+ delvePath string
+
docFile string
bazelQueryViewDir string
- delveListen string
- delvePath string
+ bp2buildMarker string
)
func init() {
+ // Flags that make sense in every mode
flag.StringVar(&topDir, "top", "", "Top directory of the Android source tree")
flag.StringVar(&outDir, "out", "", "Soong output directory (usually $TOP/out/soong)")
+ flag.StringVar(&availableEnvFile, "available_env", "", "File containing available environment variables")
+ flag.StringVar(&usedEnvFile, "used_env", "", "File containing used environment variables")
+
+ // Debug flags
flag.StringVar(&delveListen, "delve_listen", "", "Delve port to listen on for debugging")
flag.StringVar(&delvePath, "delve_path", "", "Path to Delve. Only used if --delve_listen is set")
+
+ // Flags representing various modes soong_build can run in
flag.StringVar(&docFile, "soong_docs", "", "build documentation file to output")
flag.StringVar(&bazelQueryViewDir, "bazel_queryview_dir", "", "path to the bazel queryview directory relative to --top")
+ flag.StringVar(&bp2buildMarker, "bp2build_marker", "", "If set, run bp2build, touch the specified marker file then exit")
}
func newNameResolver(config android.Config) *android.NameResolver {
@@ -75,8 +89,8 @@
return ctx
}
-func newConfig(srcDir string) android.Config {
- configuration, err := android.NewConfig(srcDir, bootstrap.CmdlineBuildDir(), bootstrap.CmdlineModuleListFile())
+func newConfig(srcDir, outDir string, availableEnv map[string]string) android.Config {
+ configuration, err := android.NewConfig(srcDir, outDir, bootstrap.CmdlineArgs.ModuleListFile, availableEnv)
if err != nil {
fmt.Fprintf(os.Stderr, "%s", err)
os.Exit(1)
@@ -90,21 +104,31 @@
// TODO(cparsons): Don't output any ninja file, as the second pass will overwrite
// the incorrect results from the first pass, and file I/O is expensive.
func runMixedModeBuild(configuration android.Config, firstCtx *android.Context, extraNinjaDeps []string) {
+ var firstArgs, secondArgs bootstrap.Args
+
+ firstArgs = bootstrap.CmdlineArgs
configuration.SetStopBefore(bootstrap.StopBeforeWriteNinja)
- bootstrap.Main(firstCtx.Context, configuration, false, extraNinjaDeps...)
+ bootstrap.RunBlueprint(firstArgs, firstCtx.Context, configuration, extraNinjaDeps...)
+
// Invoke bazel commands and save results for second pass.
if err := configuration.BazelContext.InvokeBazel(); err != nil {
fmt.Fprintf(os.Stderr, "%s", err)
os.Exit(1)
}
// Second pass: Full analysis, using the bazel command results. Output ninja file.
- secondPassConfig, err := android.ConfigForAdditionalRun(configuration)
+ secondConfig, err := android.ConfigForAdditionalRun(configuration)
if err != nil {
fmt.Fprintf(os.Stderr, "%s", err)
os.Exit(1)
}
- secondCtx := newContext(secondPassConfig, true)
- bootstrap.Main(secondCtx.Context, secondPassConfig, false, extraNinjaDeps...)
+ secondCtx := newContext(secondConfig, true)
+ secondArgs = bootstrap.CmdlineArgs
+ ninjaDeps := bootstrap.RunBlueprint(secondArgs, secondCtx.Context, secondConfig, extraNinjaDeps...)
+ err = deptools.WriteDepFile(shared.JoinPath(topDir, secondArgs.DepFile), secondArgs.OutFile, ninjaDeps)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error writing depfile '%s': %s\n", secondArgs.DepFile, err)
+ os.Exit(1)
+ }
}
// Run the code-generation phase to convert BazelTargetModules to BUILD files.
@@ -119,7 +143,8 @@
func runSoongDocs(configuration android.Config, extraNinjaDeps []string) {
ctx := newContext(configuration, false)
- bootstrap.Main(ctx.Context, configuration, false, extraNinjaDeps...)
+ soongDocsArgs := bootstrap.CmdlineArgs
+ bootstrap.RunBlueprint(soongDocsArgs, ctx.Context, configuration, extraNinjaDeps...)
if err := writeDocs(ctx, configuration, docFile); err != nil {
fmt.Fprintf(os.Stderr, "%s", err)
os.Exit(1)
@@ -127,7 +152,7 @@
}
func writeMetrics(configuration android.Config) {
- metricsFile := filepath.Join(bootstrap.CmdlineBuildDir(), "soong_build_metrics.pb")
+ metricsFile := filepath.Join(configuration.BuildDir(), "soong_build_metrics.pb")
err := android.WriteMetrics(configuration, metricsFile)
if err != nil {
fmt.Fprintf(os.Stderr, "error writing soong_build metrics %s: %s", metricsFile, err)
@@ -135,31 +160,90 @@
}
}
-func doChosenActivity(configuration android.Config, extraNinjaDeps []string) {
- bazelConversionRequested := configuration.IsEnvTrue("GENERATE_BAZEL_FILES")
+func writeJsonModuleGraph(configuration android.Config, ctx *android.Context, path string, extraNinjaDeps []string) {
+ f, err := os.Create(path)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "%s", err)
+ os.Exit(1)
+ }
+
+ defer f.Close()
+ ctx.Context.PrintJSONGraph(f)
+ writeFakeNinjaFile(extraNinjaDeps, configuration.BuildDir())
+}
+
+func doChosenActivity(configuration android.Config, extraNinjaDeps []string) string {
+ bazelConversionRequested := configuration.IsEnvTrue("GENERATE_BAZEL_FILES") || bp2buildMarker != ""
mixedModeBuild := configuration.BazelContext.BazelEnabled()
generateQueryView := bazelQueryViewDir != ""
+ jsonModuleFile := configuration.Getenv("SOONG_DUMP_JSON_MODULE_GRAPH")
+ blueprintArgs := bootstrap.CmdlineArgs
+ prepareBuildActions := !generateQueryView && jsonModuleFile == ""
if bazelConversionRequested {
// Run the alternate pipeline of bp2build mutators and singleton to convert
// Blueprint to BUILD files before everything else.
runBp2Build(configuration, extraNinjaDeps)
- return
+ if bp2buildMarker != "" {
+ return bp2buildMarker
+ } else {
+ return bootstrap.CmdlineArgs.OutFile
+ }
}
- ctx := newContext(configuration, !generateQueryView)
+ ctx := newContext(configuration, prepareBuildActions)
if mixedModeBuild {
runMixedModeBuild(configuration, ctx, extraNinjaDeps)
} else {
- bootstrap.Main(ctx.Context, configuration, false, extraNinjaDeps...)
+ ninjaDeps := bootstrap.RunBlueprint(blueprintArgs, ctx.Context, configuration, extraNinjaDeps...)
+ err := deptools.WriteDepFile(shared.JoinPath(topDir, blueprintArgs.DepFile), blueprintArgs.OutFile, ninjaDeps)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error writing depfile '%s': %s\n", blueprintArgs.DepFile, err)
+ os.Exit(1)
+ }
}
// Convert the Soong module graph into Bazel BUILD files.
if generateQueryView {
runQueryView(configuration, ctx)
- return
+ return bootstrap.CmdlineArgs.OutFile // TODO: This is a lie
}
+
+ if jsonModuleFile != "" {
+ writeJsonModuleGraph(configuration, ctx, jsonModuleFile, extraNinjaDeps)
+ return bootstrap.CmdlineArgs.OutFile // TODO: This is a lie
+ }
+
writeMetrics(configuration)
+ return bootstrap.CmdlineArgs.OutFile
+}
+
+// soong_ui dumps the available environment variables to
+// soong.environment.available . Then soong_build itself is run with an empty
+// environment so that the only way environment variables can be accessed is
+// using Config, which tracks access to them.
+
+// At the end of the build, a file called soong.environment.used is written
+// containing the current value of all used environment variables. The next
+// time soong_ui is run, it checks whether any environment variables that was
+// used had changed and if so, it deletes soong.environment.used to cause a
+// rebuild.
+//
+// The dependency of build.ninja on soong.environment.used is declared in
+// build.ninja.d
+func parseAvailableEnv() map[string]string {
+ if availableEnvFile == "" {
+ fmt.Fprintf(os.Stderr, "--available_env not set\n")
+ os.Exit(1)
+ }
+
+ result, err := shared.EnvFromFile(shared.JoinPath(topDir, availableEnvFile))
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "error reading available environment file '%s': %s\n", availableEnvFile, err)
+ os.Exit(1)
+ }
+
+ return result
}
func main() {
@@ -167,25 +251,21 @@
shared.ReexecWithDelveMaybe(delveListen, delvePath)
android.InitSandbox(topDir)
- android.InitEnvironment(shared.JoinPath(topDir, outDir, "soong.environment.available"))
- usedVariablesFile := shared.JoinPath(outDir, "soong.environment.used")
+ availableEnv := parseAvailableEnv()
+
// The top-level Blueprints file is passed as the first argument.
srcDir := filepath.Dir(flag.Arg(0))
- configuration := newConfig(srcDir)
+ configuration := newConfig(srcDir, outDir, availableEnv)
extraNinjaDeps := []string{
configuration.ProductVariablesFileName,
- shared.JoinPath(outDir, "soong.environment.used"),
+ usedEnvFile,
}
if configuration.Getenv("ALLOW_MISSING_DEPENDENCIES") == "true" {
configuration.SetAllowMissingDependencies()
}
- // These two are here so that we restart a non-debugged soong_build when the
- // user sets SOONG_DELVE the first time.
- configuration.Getenv("SOONG_DELVE")
- configuration.Getenv("SOONG_DELVE_PATH")
if shared.IsDebugging() {
// Add a non-existent file to the dependencies so that soong_build will rerun when the debugger is
// enabled even if it completed successfully.
@@ -197,35 +277,79 @@
// because that is done from within the actual builds as a Ninja action and
// thus it would overwrite the actual used variables file so this is
// special-cased.
+ // TODO: Fix this by not passing --used_env to the soong_docs invocation
runSoongDocs(configuration, extraNinjaDeps)
return
}
- doChosenActivity(configuration, extraNinjaDeps)
- writeUsedVariablesFile(shared.JoinPath(topDir, usedVariablesFile), configuration)
+ finalOutputFile := doChosenActivity(configuration, extraNinjaDeps)
+ writeUsedEnvironmentFile(configuration, finalOutputFile)
}
-func writeUsedVariablesFile(path string, configuration android.Config) {
+func writeUsedEnvironmentFile(configuration android.Config, finalOutputFile string) {
+ if usedEnvFile == "" {
+ return
+ }
+
+ path := shared.JoinPath(topDir, usedEnvFile)
data, err := shared.EnvFileContents(configuration.EnvDeps())
if err != nil {
- fmt.Fprintf(os.Stderr, "error writing used variables file %s: %s\n", path, err)
+ fmt.Fprintf(os.Stderr, "error writing used environment file '%s': %s\n", usedEnvFile, err)
os.Exit(1)
}
err = ioutil.WriteFile(path, data, 0666)
if err != nil {
- fmt.Fprintf(os.Stderr, "error writing used variables file %s: %s\n", path, err)
+ fmt.Fprintf(os.Stderr, "error writing used environment file '%s': %s\n", usedEnvFile, err)
os.Exit(1)
}
- // Touch the output Ninja file so that it's not older than the file we just
+ // Touch the output file so that it's not older than the file we just
// wrote. We can't write the environment file earlier because one an access
// new environment variables while writing it.
- outputNinjaFile := shared.JoinPath(topDir, bootstrap.CmdlineOutFile())
- currentTime := time.Now().Local()
- err = os.Chtimes(outputNinjaFile, currentTime, currentTime)
+ touch(shared.JoinPath(topDir, finalOutputFile))
+}
+
+// Workarounds to support running bp2build in a clean AOSP checkout with no
+// prior builds, and exiting early as soon as the BUILD files get generated,
+// therefore not creating build.ninja files that soong_ui and callers of
+// soong_build expects.
+//
+// These files are: build.ninja and build.ninja.d. Since Kati hasn't been
+// ran as well, and `nothing` is defined in a .mk file, there isn't a ninja
+// target called `nothing`, so we manually create it here.
+func writeFakeNinjaFile(extraNinjaDeps []string, buildDir string) {
+ extraNinjaDepsString := strings.Join(extraNinjaDeps, " \\\n ")
+
+ ninjaFileName := "build.ninja"
+ ninjaFile := shared.JoinPath(topDir, buildDir, ninjaFileName)
+ ninjaFileD := shared.JoinPath(topDir, buildDir, ninjaFileName)
+ // 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)),
+ 0666)
+}
+
+func touch(path string) {
+ f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
if err != nil {
- fmt.Fprintf(os.Stderr, "error touching output file %s: %s\n", outputNinjaFile, err)
+ fmt.Fprintf(os.Stderr, "Error touching '%s': %s\n", path, err)
+ os.Exit(1)
+ }
+
+ err = f.Close()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error touching '%s': %s\n", path, err)
+ os.Exit(1)
+ }
+
+ currentTime := time.Now().Local()
+ err = os.Chtimes(path, currentTime, currentTime)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "error touching '%s': %s\n", path, err)
os.Exit(1)
}
}
@@ -237,17 +361,18 @@
// Register an alternate set of singletons and mutators for bazel
// conversion for Bazel conversion.
bp2buildCtx := android.NewContext(configuration)
- bp2buildCtx.RegisterForBazelConversion()
- // No need to generate Ninja build rules/statements from Modules and Singletons.
- configuration.SetStopBefore(bootstrap.StopBeforePrepareBuildActions)
+ // Propagate "allow misssing dependencies" bit. This is normally set in
+ // newContext(), but we create bp2buildCtx without calling that method.
+ bp2buildCtx.SetAllowMissingDependencies(configuration.AllowMissingDependencies())
bp2buildCtx.SetNameInterface(newNameResolver(configuration))
+ bp2buildCtx.RegisterForBazelConversion()
// The bp2build process is a purely functional process that only depends on
// Android.bp files. It must not depend on the values of per-build product
// configurations or variables, since those will generate different BUILD
// files based on how the user has configured their tree.
- bp2buildCtx.SetModuleListFile(bootstrap.CmdlineModuleListFile())
+ bp2buildCtx.SetModuleListFile(bootstrap.CmdlineArgs.ModuleListFile)
modulePaths, err := bp2buildCtx.ListModulePaths(configuration.SrcDir())
if err != nil {
panic(err)
@@ -255,10 +380,25 @@
extraNinjaDeps = append(extraNinjaDeps, modulePaths...)
+ // No need to generate Ninja build rules/statements from Modules and Singletons.
+ configuration.SetStopBefore(bootstrap.StopBeforePrepareBuildActions)
+
// Run the loading and analysis pipeline to prepare the graph of regular
// Modules parsed from Android.bp files, and the BazelTargetModules mapped
// from the regular Modules.
- bootstrap.Main(bp2buildCtx.Context, configuration, false, extraNinjaDeps...)
+ blueprintArgs := bootstrap.CmdlineArgs
+ ninjaDeps := bootstrap.RunBlueprint(blueprintArgs, bp2buildCtx.Context, configuration, extraNinjaDeps...)
+
+ for _, globPath := range bp2buildCtx.Globs() {
+ ninjaDeps = append(ninjaDeps, globPath.FileListFile(configuration.BuildDir()))
+ }
+
+ depFile := bp2buildMarker + ".d"
+ err = deptools.WriteDepFile(shared.JoinPath(topDir, depFile), bp2buildMarker, ninjaDeps)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Cannot write depfile '%s': %s\n", depFile, err)
+ os.Exit(1)
+ }
// Run the code-generation phase to convert BazelTargetModules to BUILD files
// and print conversion metrics to the user.
@@ -271,30 +411,9 @@
metrics.Print()
extraNinjaDeps = append(extraNinjaDeps, codegenContext.AdditionalNinjaDeps()...)
- extraNinjaDepsString := strings.Join(extraNinjaDeps, " \\\n ")
-
- // Workarounds to support running bp2build in a clean AOSP checkout with no
- // prior builds, and exiting early as soon as the BUILD files get generated,
- // therefore not creating build.ninja files that soong_ui and callers of
- // soong_build expects.
- //
- // These files are: build.ninja and build.ninja.d. Since Kati hasn't been
- // ran as well, and `nothing` is defined in a .mk file, there isn't a ninja
- // target called `nothing`, so we manually create it here.
- //
- // Even though outFile (build.ninja) and depFile (build.ninja.d) are values
- // passed into bootstrap.Main, they are package-private fields in bootstrap.
- // Short of modifying Blueprint to add an exported getter, inlining them
- // here is the next-best practical option.
- ninjaFileName := "build.ninja"
- ninjaFile := android.PathForOutput(codegenContext, ninjaFileName)
- ninjaFileD := android.PathForOutput(codegenContext, 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.
- android.WriteFileToOutputDir(ninjaFile, []byte("build nothing: phony\n phony_output = true\n"), 0666)
- android.WriteFileToOutputDir(
- ninjaFileD,
- []byte(fmt.Sprintf("%s: \\\n %s\n", ninjaFileName, extraNinjaDepsString)),
- 0666)
+ if bp2buildMarker != "" {
+ touch(shared.JoinPath(topDir, bp2buildMarker))
+ } else {
+ writeFakeNinjaFile(extraNinjaDeps, codegenContext.Config().BuildDir())
+ }
}
diff --git a/docs/map_files.md b/docs/map_files.md
index 9fc0d14..192530f 100644
--- a/docs/map_files.md
+++ b/docs/map_files.md
@@ -52,7 +52,8 @@
symbol visibility of the library to expose only the interface named by the map
file. Without this, APIs that you have not explicitly exposed will still be
available to users via `dlsym`. Note: All comments are ignored in this case. Any
-symbol named in any `global:` group will be visible.
+symbol named in any `global:` group will be visible in the implementation
+library. Annotations in comments only affect what is exposed by the stubs.
## Special version names
@@ -76,9 +77,13 @@
### future
Indicates that the version or symbol is first introduced in the "future" API
-level. This is an abitrarily high API level used to define APIs that have not
+level. This is an arbitrarily high API level used to define APIs that have not
yet been added to a specific release.
+Warning: APIs marked `future` will be usable in any module with `sdk: "current"`
+but **will not be included in the NDK**. `future` should generally not be used,
+but is useful when developing APIs for an unknown future release.
+
### introduced
Indicates the version in which an API was first introduced. For example,
@@ -92,13 +97,15 @@
determine which API level an API was added in. The `first_version` property of
`ndk_library` will dictate which API levels stubs are generated for. If the
module sets `first_version: "21"`, no symbols were introduced before API 21.
+**Symbol names for which no other rule applies will implicitly be introduced in
+`first_version`.**
-Codenames can (and typically should) be used when defining new APIs. This allows
-the actual number of the API level to remain vague during development of that
-release. For example, `introduced=S` can be used to define APIs added in S. Any
-code name known to the build system can be used. For a list of versions known to
-the build system, see `out/soong/api_levels.json` (if not present, run `m
-out/soong/api_levels.json` to generate it).
+Code names can (and typically should) be used when defining new APIs. This
+allows the actual number of the API level to remain vague during development of
+that release. For example, `introduced=S` can be used to define APIs added in S.
+Any code name known to the build system can be used. For a list of versions
+known to the build system, see `out/soong/api_levels.json` (if not present, run
+`m out/soong/api_levels.json` to generate it).
Architecture-specific variants of this tag exist:
@@ -123,6 +130,8 @@
than the NDK. May be used in combination with `apex` if the symbol is exposed to
both APEX and the LL-NDK.
+Historically this annotation was spelled `vndk`, but it has always meant LL-NDK.
+
### platform-only
Indicates that the version or symbol is public in the implementation library but
@@ -131,9 +140,9 @@
clear to the developer that they are up to no good.
The typical use for this tag is for exposing an API to the platform that is not
-for use by the NDK, LL-NDK, or APEX. It is preferable to keep such APIs in an
-entirely separate library to protect them from access via `dlsym`, but this is
-not always possible.
+for use by the NDK, LL-NDK, or APEX (similar to Java's `@SystemAPI`). It is
+preferable to keep such APIs in an entirely separate library to protect them
+from access via `dlsym`, but this is not always possible.
### var
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index 6291325..3204e70 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -29,6 +29,7 @@
import (
"fmt"
+ "strings"
"github.com/google/blueprint/proptools"
@@ -47,6 +48,7 @@
func RegisterPrebuiltEtcBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("prebuilt_etc", PrebuiltEtcFactory)
ctx.RegisterModuleType("prebuilt_etc_host", PrebuiltEtcHostFactory)
+ ctx.RegisterModuleType("prebuilt_root", PrebuiltRootFactory)
ctx.RegisterModuleType("prebuilt_usr_share", PrebuiltUserShareFactory)
ctx.RegisterModuleType("prebuilt_usr_share_host", PrebuiltUserShareHostFactory)
ctx.RegisterModuleType("prebuilt_font", PrebuiltFontFactory)
@@ -60,14 +62,6 @@
// Source file of this prebuilt. Can reference a genrule type module with the ":module" syntax.
Src *string `android:"path,arch_variant"`
- // Optional subdirectory under which this file is installed into, cannot be specified with
- // relative_install_path, prefer relative_install_path.
- Sub_dir *string `android:"arch_variant"`
-
- // Optional subdirectory under which this file is installed into, cannot be specified with
- // sub_dir.
- Relative_install_path *string `android:"arch_variant"`
-
// Optional name for the installed file. If unspecified, name of the module is used as the file
// name.
Filename *string `android:"arch_variant"`
@@ -90,6 +84,13 @@
// the recovery variant instead.
Vendor_ramdisk_available *bool
+ // Make this module available when building for debug ramdisk.
+ // On device without a dedicated recovery partition, the module is only
+ // available after switching root into
+ // /first_stage_ramdisk. To expose the module before switching root, install
+ // the recovery variant instead.
+ Debug_ramdisk_available *bool
+
// Make this module available when building for recovery.
Recovery_available *bool
@@ -100,6 +101,16 @@
Symlinks []string `android:"arch_variant"`
}
+type prebuiltSubdirProperties struct {
+ // Optional subdirectory under which this file is installed into, cannot be specified with
+ // relative_install_path, prefer relative_install_path.
+ Sub_dir *string `android:"arch_variant"`
+
+ // Optional subdirectory under which this file is installed into, cannot be specified with
+ // sub_dir.
+ Relative_install_path *string `android:"arch_variant"`
+}
+
type PrebuiltEtcModule interface {
android.Module
@@ -117,7 +128,8 @@
type PrebuiltEtc struct {
android.ModuleBase
- properties prebuiltEtcProperties
+ properties prebuiltEtcProperties
+ subdirProperties prebuiltSubdirProperties
sourceFilePath android.Path
outputFilePath android.OutputPath
@@ -154,6 +166,18 @@
return p.inVendorRamdisk()
}
+func (p *PrebuiltEtc) inDebugRamdisk() bool {
+ return p.ModuleBase.InDebugRamdisk() || p.ModuleBase.InstallInDebugRamdisk()
+}
+
+func (p *PrebuiltEtc) onlyInDebugRamdisk() bool {
+ return p.ModuleBase.InstallInDebugRamdisk()
+}
+
+func (p *PrebuiltEtc) InstallInDebugRamdisk() bool {
+ return p.inDebugRamdisk()
+}
+
func (p *PrebuiltEtc) inRecovery() bool {
return p.ModuleBase.InRecovery() || p.ModuleBase.InstallInRecovery()
}
@@ -172,7 +196,7 @@
func (p *PrebuiltEtc) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
return !p.ModuleBase.InstallInRecovery() && !p.ModuleBase.InstallInRamdisk() &&
- !p.ModuleBase.InstallInVendorRamdisk()
+ !p.ModuleBase.InstallInVendorRamdisk() && !p.ModuleBase.InstallInDebugRamdisk()
}
func (p *PrebuiltEtc) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
@@ -183,6 +207,10 @@
return proptools.Bool(p.properties.Vendor_ramdisk_available) || p.ModuleBase.InstallInVendorRamdisk()
}
+func (p *PrebuiltEtc) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+ return proptools.Bool(p.properties.Debug_ramdisk_available) || p.ModuleBase.InstallInDebugRamdisk()
+}
+
func (p *PrebuiltEtc) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
return proptools.Bool(p.properties.Recovery_available) || p.ModuleBase.InstallInRecovery()
}
@@ -224,10 +252,10 @@
}
func (p *PrebuiltEtc) SubDir() string {
- if subDir := proptools.String(p.properties.Sub_dir); subDir != "" {
+ if subDir := proptools.String(p.subdirProperties.Sub_dir); subDir != "" {
return subDir
}
- return proptools.String(p.properties.Relative_install_path)
+ return proptools.String(p.subdirProperties.Relative_install_path)
}
func (p *PrebuiltEtc) BaseDir() string {
@@ -263,8 +291,13 @@
}
p.outputFilePath = android.PathForModuleOut(ctx, filename).OutputPath
+ if strings.Contains(filename, "/") {
+ ctx.PropertyErrorf("filename", "filename cannot contain separator '/'")
+ return
+ }
+
// Check that `sub_dir` and `relative_install_path` are not set at the same time.
- if p.properties.Sub_dir != nil && p.properties.Relative_install_path != nil {
+ if p.subdirProperties.Sub_dir != nil && p.subdirProperties.Relative_install_path != nil {
ctx.PropertyErrorf("sub_dir", "relative_install_path is set. Cannot set sub_dir")
}
@@ -303,6 +336,9 @@
if p.inVendorRamdisk() && !p.onlyInVendorRamdisk() {
nameSuffix = ".vendor_ramdisk"
}
+ if p.inDebugRamdisk() && !p.onlyInDebugRamdisk() {
+ nameSuffix = ".debug_ramdisk"
+ }
if p.inRecovery() && !p.onlyInRecovery() {
nameSuffix = ".recovery"
}
@@ -330,6 +366,12 @@
func InitPrebuiltEtcModule(p *PrebuiltEtc, dirBase string) {
p.installDirBase = dirBase
p.AddProperties(&p.properties)
+ p.AddProperties(&p.subdirProperties)
+}
+
+func InitPrebuiltRootModule(p *PrebuiltEtc) {
+ p.installDirBase = "."
+ p.AddProperties(&p.properties)
}
// prebuilt_etc is for a prebuilt artifact that is installed in
@@ -352,6 +394,16 @@
return module
}
+// prebuilt_root is for a prebuilt artifact that is installed in
+// <partition>/ directory. Can't have any sub directories.
+func PrebuiltRootFactory() android.Module {
+ module := &PrebuiltEtc{}
+ InitPrebuiltRootModule(module)
+ // This module is device-only
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
+ return module
+}
+
// prebuilt_usr_share is for a prebuilt artifact that is installed in
// <partition>/usr/share/<sub_dir> directory.
func PrebuiltUserShareFactory() android.Module {
diff --git a/etc/prebuilt_etc_test.go b/etc/prebuilt_etc_test.go
index 9c3db3b..fdb5648 100644
--- a/etc/prebuilt_etc_test.go
+++ b/etc/prebuilt_etc_test.go
@@ -179,6 +179,30 @@
}
}
+func TestPrebuiltRootInstallDirPath(t *testing.T) {
+ result := prepareForPrebuiltEtcTest.RunTestWithBp(t, `
+ prebuilt_root {
+ name: "foo.conf",
+ src: "foo.conf",
+ filename: "foo.conf",
+ }
+ `)
+
+ p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc)
+ expected := "out/soong/target/product/test_device/system"
+ android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath)
+}
+
+func TestPrebuiltRootInstallDirPathValidate(t *testing.T) {
+ prepareForPrebuiltEtcTest.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern("filename cannot contain separator")).RunTestWithBp(t, `
+ prebuilt_root {
+ name: "foo.conf",
+ src: "foo.conf",
+ filename: "foo/bar.conf",
+ }
+ `)
+}
+
func TestPrebuiltUserShareInstallDirPath(t *testing.T) {
result := prepareForPrebuiltEtcTest.RunTestWithBp(t, `
prebuilt_usr_share {
diff --git a/filesystem/bootimg.go b/filesystem/bootimg.go
index 3dcc416..29a8a39 100644
--- a/filesystem/bootimg.go
+++ b/filesystem/bootimg.go
@@ -61,7 +61,7 @@
Vendor_boot *bool
// Optional kernel commandline
- Cmdline *string
+ Cmdline *string `android:"arch_variant"`
// File that contains bootconfig parameters. This can be set only when `vendor_boot` is true
// and `header_version` is greater than or equal to 4.
diff --git a/filesystem/vbmeta.go b/filesystem/vbmeta.go
index f823387..3f16c0d 100644
--- a/filesystem/vbmeta.go
+++ b/filesystem/vbmeta.go
@@ -110,6 +110,9 @@
return proptools.StringDefault(v.properties.Partition_name, v.BaseModuleName())
}
+// See external/avb/libavb/avb_slot_verify.c#VBMETA_MAX_SIZE
+const vbmetaMaxSize = 64 * 1024
+
func (v *vbmeta) GenerateAndroidBuildActions(ctx android.ModuleContext) {
extractedPublicKeys := v.extractPublicKeys(ctx)
@@ -172,6 +175,13 @@
}
cmd.FlagWithOutput("--output ", v.output)
+
+ // libavb expects to be able to read the maximum vbmeta size, so we must provide a partition
+ // which matches this or the read will fail.
+ builder.Command().Text("truncate").
+ FlagWithArg("-s ", strconv.Itoa(vbmetaMaxSize)).
+ Output(v.output)
+
builder.Build("vbmeta", fmt.Sprintf("vbmeta %s", ctx.ModuleName()))
v.installDir = android.PathForModuleInstall(ctx, "etc")
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 5d438ea..e6a5ab9 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -229,11 +229,16 @@
filePaths, ok := bazelCtx.GetOutputFiles(label, ctx.Arch().ArchType)
if ok {
var bazelOutputFiles android.Paths
+ exportIncludeDirs := map[string]bool{}
for _, bazelOutputFile := range filePaths {
bazelOutputFiles = append(bazelOutputFiles, android.PathForBazelOut(ctx, bazelOutputFile))
+ exportIncludeDirs[filepath.Dir(bazelOutputFile)] = true
}
c.outputFiles = bazelOutputFiles
c.outputDeps = bazelOutputFiles
+ for includePath, _ := range exportIncludeDirs {
+ c.exportedIncludeDirs = append(c.exportedIncludeDirs, android.PathForBazelOut(ctx, includePath))
+ }
}
return ok
}
@@ -621,6 +626,7 @@
func (x noopImageInterface) CoreVariantNeeded(android.BaseModuleContext) bool { return false }
func (x noopImageInterface) RamdiskVariantNeeded(android.BaseModuleContext) bool { return false }
func (x noopImageInterface) VendorRamdiskVariantNeeded(android.BaseModuleContext) bool { return false }
+func (x noopImageInterface) DebugRamdiskVariantNeeded(android.BaseModuleContext) bool { return false }
func (x noopImageInterface) RecoveryVariantNeeded(android.BaseModuleContext) bool { return false }
func (x noopImageInterface) ExtraImageVariations(ctx android.BaseModuleContext) []string { return nil }
func (x noopImageInterface) SetImageVariation(ctx android.BaseModuleContext, variation string, module android.Module) {
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index 3f1e9f3..3ce4f85 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -696,7 +696,8 @@
result := android.GroupFixturePreparers(
prepareForGenRuleTest, android.FixtureModifyConfig(func(config android.Config) {
config.BazelContext = android.MockBazelContext{
- AllFiles: map[string][]string{
+ OutputBaseDir: "outputbase",
+ LabelToOutputFiles: map[string][]string{
"//foo/bar:bar": []string{"bazelone.txt", "bazeltwo.txt"}}}
})).RunTestWithBp(t, testGenruleBp()+bp)
diff --git a/java/Android.bp b/java/Android.bp
index 8334b85..2a4b596 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -32,6 +32,7 @@
"boot_image.go",
"boot_jars.go",
"builder.go",
+ "classpath_fragment.go",
"device_host_converter.go",
"dex.go",
"dexpreopt.go",
@@ -42,6 +43,7 @@
"gen.go",
"genrule.go",
"hiddenapi.go",
+ "hiddenapi_modular.go",
"hiddenapi_singleton.go",
"jacoco.go",
"java.go",
diff --git a/java/aar.go b/java/aar.go
index a122a94..04727e4 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -218,7 +218,7 @@
linkDeps = append(linkDeps, assetDeps...)
// SDK version flags
- minSdkVersion, err := sdkContext.MinSdkVersion().EffectiveVersionString(ctx)
+ minSdkVersion, err := sdkContext.MinSdkVersion(ctx).EffectiveVersionString(ctx)
if err != nil {
ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
}
@@ -609,6 +609,9 @@
hideApexVariantFromMake bool
aarPath android.Path
+
+ sdkVersion android.SdkSpec
+ minSdkVersion android.SdkSpec
}
var _ android.OutputFileProducer = (*AARImport)(nil)
@@ -625,23 +628,23 @@
}
}
-func (a *AARImport) SdkVersion() android.SdkSpec {
- return android.SdkSpecFrom(String(a.properties.Sdk_version))
+func (a *AARImport) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+ return android.SdkSpecFrom(ctx, String(a.properties.Sdk_version))
}
func (a *AARImport) SystemModules() string {
return ""
}
-func (a *AARImport) MinSdkVersion() android.SdkSpec {
+func (a *AARImport) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
if a.properties.Min_sdk_version != nil {
- return android.SdkSpecFrom(*a.properties.Min_sdk_version)
+ return android.SdkSpecFrom(ctx, *a.properties.Min_sdk_version)
}
- return a.SdkVersion()
+ return a.SdkVersion(ctx)
}
-func (a *AARImport) TargetSdkVersion() android.SdkSpec {
- return a.SdkVersion()
+func (a *AARImport) TargetSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+ return a.SdkVersion(ctx)
}
func (a *AARImport) javaVersion() string {
@@ -727,6 +730,9 @@
return
}
+ a.sdkVersion = a.SdkVersion(ctx)
+ a.minSdkVersion = a.MinSdkVersion(ctx)
+
a.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform()
aarName := ctx.ModuleName() + ".aar"
diff --git a/java/android_manifest.go b/java/android_manifest.go
index 6b7395b..331f941 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -51,11 +51,11 @@
if isLibrary {
args = append(args, "--library")
} else {
- minSdkVersion, err := sdkContext.MinSdkVersion().EffectiveVersion(ctx)
+ minSdkVersion, err := sdkContext.MinSdkVersion(ctx).EffectiveVersion(ctx)
if err != nil {
ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
}
- if minSdkVersion >= 23 {
+ if minSdkVersion.FinalOrFutureInt() >= 23 {
args = append(args, fmt.Sprintf("--extract-native-libs=%v", !useEmbeddedNativeLibs))
} else if useEmbeddedNativeLibs {
ctx.ModuleErrorf("module attempted to store uncompressed native libraries, but minSdkVersion=%d doesn't support it",
@@ -87,7 +87,7 @@
args = append(args, "--logging-parent", loggingParent)
}
var deps android.Paths
- targetSdkVersion, err := sdkContext.TargetSdkVersion().EffectiveVersionString(ctx)
+ targetSdkVersion, err := sdkContext.TargetSdkVersion(ctx).EffectiveVersionString(ctx)
if err != nil {
ctx.ModuleErrorf("invalid targetSdkVersion: %s", err)
}
@@ -96,7 +96,7 @@
deps = append(deps, ApiFingerprintPath(ctx))
}
- minSdkVersion, err := sdkContext.MinSdkVersion().EffectiveVersionString(ctx)
+ minSdkVersion, err := sdkContext.MinSdkVersion(ctx).EffectiveVersionString(ctx)
if err != nil {
ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
}
diff --git a/java/androidmk.go b/java/androidmk.go
index 75661a7..4e594a2 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -106,7 +106,7 @@
if len(library.dexpreopter.builtInstalled) > 0 {
entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", library.dexpreopter.builtInstalled)
}
- entries.SetString("LOCAL_SDK_VERSION", library.SdkVersion().Raw)
+ entries.SetString("LOCAL_SDK_VERSION", library.sdkVersion.String())
entries.SetPath("LOCAL_SOONG_CLASSES_JAR", library.implementationAndResourcesJar)
entries.SetPath("LOCAL_SOONG_HEADER_JAR", library.headerJarFile)
@@ -205,7 +205,7 @@
}
entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.combinedClasspathFile)
entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.combinedClasspathFile)
- entries.SetString("LOCAL_SDK_VERSION", prebuilt.makeSdkVersion())
+ entries.SetString("LOCAL_SDK_VERSION", prebuilt.sdkVersion.String())
entries.SetString("LOCAL_MODULE_STEM", prebuilt.Stem())
},
},
@@ -255,7 +255,7 @@
entries.SetPath("LOCAL_SOONG_EXPORT_PROGUARD_FLAGS", prebuilt.proguardFlags)
entries.SetPath("LOCAL_SOONG_STATIC_LIBRARY_EXTRA_PACKAGES", prebuilt.extraAaptPackagesFile)
entries.SetPath("LOCAL_FULL_MANIFEST_FILE", prebuilt.manifest)
- entries.SetString("LOCAL_SDK_VERSION", prebuilt.SdkVersion().Raw)
+ entries.SetString("LOCAL_SDK_VERSION", prebuilt.sdkVersion.String())
},
},
}}
diff --git a/java/app.go b/java/app.go
index ec30b49..5695022 100755
--- a/java/app.go
+++ b/java/app.go
@@ -213,7 +213,7 @@
func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) {
a.Module.deps(ctx)
- if String(a.appProperties.Stl) == "c++_shared" && !a.SdkVersion().Specified() {
+ if String(a.appProperties.Stl) == "c++_shared" && !a.SdkVersion(ctx).Specified() {
ctx.PropertyErrorf("stl", "sdk_version must be set in order to use c++_shared")
}
@@ -222,7 +222,7 @@
a.aapt.deps(ctx, sdkDep)
}
- usesSDK := a.SdkVersion().Specified() && a.SdkVersion().Kind != android.SdkCorePlatform
+ usesSDK := a.SdkVersion(ctx).Specified() && a.SdkVersion(ctx).Kind != android.SdkCorePlatform
if usesSDK && Bool(a.appProperties.Jni_uses_sdk_apis) {
ctx.PropertyErrorf("jni_uses_sdk_apis",
@@ -279,16 +279,16 @@
func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) {
if a.Updatable() {
- if !a.SdkVersion().Stable() {
- ctx.PropertyErrorf("sdk_version", "Updatable apps must use stable SDKs, found %v", a.SdkVersion())
+ if !a.SdkVersion(ctx).Stable() {
+ ctx.PropertyErrorf("sdk_version", "Updatable apps must use stable SDKs, found %v", a.SdkVersion(ctx))
}
if String(a.deviceProperties.Min_sdk_version) == "" {
ctx.PropertyErrorf("updatable", "updatable apps must set min_sdk_version.")
}
- if minSdkVersion, err := a.MinSdkVersion().EffectiveVersion(ctx); err == nil {
+ if minSdkVersion, err := a.MinSdkVersion(ctx).EffectiveVersion(ctx); err == nil {
a.checkJniLibsSdkVersion(ctx, minSdkVersion)
- android.CheckMinSdkVersion(a, ctx, minSdkVersion.ApiLevel(ctx))
+ android.CheckMinSdkVersion(a, ctx, minSdkVersion)
} else {
ctx.PropertyErrorf("min_sdk_version", "%s", err.Error())
}
@@ -304,7 +304,7 @@
// because, sdk_version is overridden by min_sdk_version (if set as smaller)
// and sdkLinkType is checked with dependencies so we can be sure that the whole dependency tree
// will meet the requirements.
-func (a *AndroidApp) checkJniLibsSdkVersion(ctx android.ModuleContext, minSdkVersion android.SdkVersion) {
+func (a *AndroidApp) checkJniLibsSdkVersion(ctx android.ModuleContext, minSdkVersion android.ApiLevel) {
// It's enough to check direct JNI deps' sdk_version because all transitive deps from JNI deps are checked in cc.checkLinkType()
ctx.VisitDirectDeps(func(m android.Module) {
if !IsJniDepTag(ctx.OtherModuleDependencyTag(m)) {
@@ -314,8 +314,8 @@
// The domain of cc.sdk_version is "current" and <number>
// We can rely on android.SdkSpec to convert it to <number> so that "current" is
// handled properly regardless of sdk finalization.
- jniSdkVersion, err := android.SdkSpecFrom(dep.SdkVersion()).EffectiveVersion(ctx)
- if err != nil || minSdkVersion < jniSdkVersion {
+ jniSdkVersion, err := android.SdkSpecFrom(ctx, dep.SdkVersion()).EffectiveVersion(ctx)
+ if err != nil || minSdkVersion.LessThan(jniSdkVersion) {
ctx.OtherModuleErrorf(dep, "sdk_version(%v) is higher than min_sdk_version(%v) of the containing android_app(%v)",
dep.SdkVersion(), minSdkVersion, ctx.ModuleName())
return
@@ -327,13 +327,13 @@
// Returns true if the native libraries should be stored in the APK uncompressed and the
// extractNativeLibs application flag should be set to false in the manifest.
func (a *AndroidApp) useEmbeddedNativeLibs(ctx android.ModuleContext) bool {
- minSdkVersion, err := a.MinSdkVersion().EffectiveVersion(ctx)
+ minSdkVersion, err := a.MinSdkVersion(ctx).EffectiveVersion(ctx)
if err != nil {
- ctx.PropertyErrorf("min_sdk_version", "invalid value %q: %s", a.MinSdkVersion(), err)
+ ctx.PropertyErrorf("min_sdk_version", "invalid value %q: %s", a.MinSdkVersion(ctx), err)
}
apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
- return (minSdkVersion >= 23 && Bool(a.appProperties.Use_embedded_native_libs)) ||
+ return (minSdkVersion.FinalOrFutureInt() >= 23 && Bool(a.appProperties.Use_embedded_native_libs)) ||
!apexInfo.IsForPlatform()
}
@@ -380,7 +380,11 @@
}
func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) {
- a.aapt.usesNonSdkApis = Bool(a.Module.deviceProperties.Platform_apis)
+ usePlatformAPI := proptools.Bool(a.Module.deviceProperties.Platform_apis)
+ if ctx.Module().(android.SdkContext).SdkVersion(ctx).Kind == android.SdkModule {
+ usePlatformAPI = true
+ }
+ a.aapt.usesNonSdkApis = usePlatformAPI
// Ask manifest_fixer to add or update the application element indicating this app has no code.
a.aapt.hasNoCode = !a.hasCode(ctx)
@@ -720,8 +724,8 @@
}
type appDepsInterface interface {
- SdkVersion() android.SdkSpec
- MinSdkVersion() android.SdkSpec
+ SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec
+ MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec
RequiresStableAPIs(ctx android.BaseModuleContext) bool
}
@@ -734,8 +738,8 @@
seenModulePaths := make(map[string]bool)
if checkNativeSdkVersion {
- checkNativeSdkVersion = app.SdkVersion().Specified() &&
- app.SdkVersion().Kind != android.SdkCorePlatform && !app.RequiresStableAPIs(ctx)
+ checkNativeSdkVersion = app.SdkVersion(ctx).Specified() &&
+ app.SdkVersion(ctx).Kind != android.SdkCorePlatform && !app.RequiresStableAPIs(ctx)
}
ctx.WalkDeps(func(module android.Module, parent android.Module) bool {
@@ -825,12 +829,16 @@
depsInfo[depName] = info
} else {
toMinSdkVersion := "(no version)"
- if m, ok := to.(interface{ MinSdkVersion() string }); ok {
- if v := m.MinSdkVersion(); v != "" {
- toMinSdkVersion = v
+ if m, ok := to.(interface {
+ MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec
+ }); ok {
+ if v := m.MinSdkVersion(ctx); !v.ApiLevel.IsNone() {
+ toMinSdkVersion = v.ApiLevel.String()
}
- } else if m, ok := to.(interface{ MinSdkVersionString() string }); ok {
- if v := m.MinSdkVersionString(); v != "" {
+ } else if m, ok := to.(interface{ MinSdkVersion() string }); ok {
+ // TODO(b/175678607) eliminate the use of MinSdkVersion returning
+ // string
+ if v := m.MinSdkVersion(); v != "" {
toMinSdkVersion = v
}
}
@@ -844,7 +852,7 @@
return true
})
- a.ApexBundleDepsInfo.BuildDepsInfoLists(ctx, a.MinSdkVersionString(), depsInfo)
+ a.ApexBundleDepsInfo.BuildDepsInfoLists(ctx, a.MinSdkVersion(ctx).String(), depsInfo)
}
func (a *AndroidApp) Updatable() bool {
diff --git a/java/app_import.go b/java/app_import.go
index 32cec23..839051e 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -394,12 +394,12 @@
return false
}
-func (a *AndroidAppImport) SdkVersion() android.SdkSpec {
- return android.SdkSpecFrom("")
+func (a *AndroidAppImport) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+ return android.SdkSpecPrivate
}
-func (a *AndroidAppImport) MinSdkVersion() android.SdkSpec {
- return android.SdkSpecFrom("")
+func (a *AndroidAppImport) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+ return android.SdkSpecPrivate
}
var _ android.ApexModule = (*AndroidAppImport)(nil)
diff --git a/java/base.go b/java/base.go
index 73e5352..19c85cd 100644
--- a/java/base.go
+++ b/java/base.go
@@ -370,10 +370,13 @@
modulePaths []string
hideApexVariantFromMake bool
+
+ sdkVersion android.SdkSpec
+ minSdkVersion android.SdkSpec
}
-func (j *Module) CheckStableSdkVersion() error {
- sdkVersion := j.SdkVersion()
+func (j *Module) CheckStableSdkVersion(ctx android.BaseModuleContext) error {
+ sdkVersion := j.SdkVersion(ctx)
if sdkVersion.Stable() {
return nil
}
@@ -393,7 +396,7 @@
func (j *Module) checkSdkVersions(ctx android.ModuleContext) {
if j.RequiresStableAPIs(ctx) {
if sc, ok := ctx.Module().(android.SdkContext); ok {
- if !sc.SdkVersion().Specified() {
+ if !sc.SdkVersion(ctx).Specified() {
ctx.PropertyErrorf("sdk_version",
"sdk_version must have a value when the module is located at vendor or product(only if PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE is set).")
}
@@ -418,7 +421,7 @@
func (j *Module) checkPlatformAPI(ctx android.ModuleContext) {
if sc, ok := ctx.Module().(android.SdkContext); ok {
usePlatformAPI := proptools.Bool(j.deviceProperties.Platform_apis)
- sdkVersionSpecified := sc.SdkVersion().Specified()
+ sdkVersionSpecified := sc.SdkVersion(ctx).Specified()
if usePlatformAPI && sdkVersionSpecified {
ctx.PropertyErrorf("platform_apis", "platform_apis must be false when sdk_version is not empty.")
} else if !usePlatformAPI && !sdkVersionSpecified {
@@ -512,30 +515,30 @@
return false
}
-func (j *Module) SdkVersion() android.SdkSpec {
- return android.SdkSpecFrom(String(j.deviceProperties.Sdk_version))
+func (j *Module) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+ return android.SdkSpecFrom(ctx, String(j.deviceProperties.Sdk_version))
}
func (j *Module) SystemModules() string {
return proptools.String(j.deviceProperties.System_modules)
}
-func (j *Module) MinSdkVersion() android.SdkSpec {
+func (j *Module) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
if j.deviceProperties.Min_sdk_version != nil {
- return android.SdkSpecFrom(*j.deviceProperties.Min_sdk_version)
+ return android.SdkSpecFrom(ctx, *j.deviceProperties.Min_sdk_version)
}
- return j.SdkVersion()
-}
-
-func (j *Module) TargetSdkVersion() android.SdkSpec {
- if j.deviceProperties.Target_sdk_version != nil {
- return android.SdkSpecFrom(*j.deviceProperties.Target_sdk_version)
- }
- return j.SdkVersion()
+ return j.SdkVersion(ctx)
}
func (j *Module) MinSdkVersionString() string {
- return j.MinSdkVersion().Version.String()
+ return j.minSdkVersion.Raw
+}
+
+func (j *Module) TargetSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+ if j.deviceProperties.Target_sdk_version != nil {
+ return android.SdkSpecFrom(ctx, *j.deviceProperties.Target_sdk_version)
+ }
+ return j.SdkVersion(ctx)
}
func (j *Module) AvailableFor(what string) bool {
@@ -1209,7 +1212,7 @@
}
// Dex compilation
var dexOutputFile android.OutputPath
- dexOutputFile = j.dexer.compileDex(ctx, flags, j.MinSdkVersion(), outputFile, jarName)
+ dexOutputFile = j.dexer.compileDex(ctx, flags, j.MinSdkVersion(ctx), outputFile, jarName)
if ctx.Failed() {
return
}
@@ -1255,7 +1258,7 @@
if ctx.Device() {
lintSDKVersionString := func(sdkSpec android.SdkSpec) string {
- if v := sdkSpec.Version; v.IsNumbered() {
+ if v := sdkSpec.ApiLevel; !v.IsPreview() {
return v.String()
} else {
return ctx.Config().DefaultAppTargetSdk(ctx).String()
@@ -1267,9 +1270,9 @@
j.linter.srcJars = srcJars
j.linter.classpath = append(append(android.Paths(nil), flags.bootClasspath...), flags.classpath...)
j.linter.classes = j.implementationJarFile
- j.linter.minSdkVersion = lintSDKVersionString(j.MinSdkVersion())
- j.linter.targetSdkVersion = lintSDKVersionString(j.TargetSdkVersion())
- j.linter.compileSdkVersion = lintSDKVersionString(j.SdkVersion())
+ j.linter.minSdkVersion = lintSDKVersionString(j.MinSdkVersion(ctx))
+ j.linter.targetSdkVersion = lintSDKVersionString(j.TargetSdkVersion(ctx))
+ j.linter.compileSdkVersion = lintSDKVersionString(j.SdkVersion(ctx))
j.linter.javaLanguageLevel = flags.javaVersion.String()
j.linter.kotlinLanguageLevel = "1.3"
if !apexInfo.IsForPlatform() && ctx.Config().UnbundledBuildApps() {
@@ -1471,7 +1474,7 @@
// Implements android.ApexModule
func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
sdkVersion android.ApiLevel) error {
- sdkSpec := j.MinSdkVersion()
+ sdkSpec := j.MinSdkVersion(ctx)
if !sdkSpec.Specified() {
return fmt.Errorf("min_sdk_version is not specified")
}
@@ -1482,7 +1485,7 @@
if err != nil {
return err
}
- if ver.ApiLevel(ctx).GreaterThan(sdkVersion) {
+ if ver.GreaterThan(sdkVersion) {
return fmt.Errorf("newer SDK(%v)", ver)
}
return nil
@@ -1551,10 +1554,10 @@
type moduleWithSdkDep interface {
android.Module
- getSdkLinkType(name string) (ret sdkLinkType, stubs bool)
+ getSdkLinkType(ctx android.BaseModuleContext, name string) (ret sdkLinkType, stubs bool)
}
-func (m *Module) getSdkLinkType(name string) (ret sdkLinkType, stubs bool) {
+func (m *Module) getSdkLinkType(ctx android.BaseModuleContext, name string) (ret sdkLinkType, stubs bool) {
switch name {
case "core.current.stubs", "legacy.core.platform.api.stubs", "stable.core.platform.api.stubs",
"stub-annotations", "private-stub-annotations-jar",
@@ -1576,7 +1579,7 @@
return linkType, true
}
- ver := m.SdkVersion()
+ ver := m.SdkVersion(ctx)
switch ver.Kind {
case android.SdkCore:
return javaCore, false
@@ -1606,11 +1609,11 @@
return
}
- myLinkType, stubs := j.getSdkLinkType(ctx.ModuleName())
+ myLinkType, stubs := j.getSdkLinkType(ctx, ctx.ModuleName())
if stubs {
return
}
- depLinkType, _ := dep.getSdkLinkType(ctx.OtherModuleName(dep))
+ depLinkType, _ := dep.getSdkLinkType(ctx, ctx.OtherModuleName(dep))
if myLinkType.rank() < depLinkType.rank() {
ctx.ModuleErrorf("compiles against %v, but dependency %q is compiling against %v. "+
@@ -1638,7 +1641,7 @@
}
}
- sdkLinkType, _ := j.getSdkLinkType(ctx.ModuleName())
+ sdkLinkType, _ := j.getSdkLinkType(ctx, ctx.ModuleName())
ctx.VisitDirectDeps(func(module android.Module) {
otherName := ctx.OtherModuleName(module)
@@ -1656,7 +1659,7 @@
if dep, ok := module.(SdkLibraryDependency); ok {
switch tag {
case libTag:
- deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion())...)
+ deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))...)
case staticLibTag:
ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName)
}
diff --git a/java/boot_jars.go b/java/boot_jars.go
index ac8107b..1fb3deb 100644
--- a/java/boot_jars.go
+++ b/java/boot_jars.go
@@ -56,16 +56,7 @@
if !module.Enabled() {
return false
}
- if module.IsReplacedByPrebuilt() {
- // A source module that has been replaced by a prebuilt counterpart.
- return false
- }
- if prebuilt, ok := module.(android.PrebuiltInterface); ok {
- if p := prebuilt.Prebuilt(); p != nil {
- return p.UsePrebuilt()
- }
- }
- return true
+ return android.IsModulePreferred(module)
}
func (b *bootJarsSingleton) GenerateBuildActions(ctx android.SingletonContext) {
diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go
new file mode 100644
index 0000000..d497460
--- /dev/null
+++ b/java/classpath_fragment.go
@@ -0,0 +1,151 @@
+/*
+ * 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 (
+ "fmt"
+ "strings"
+
+ "android/soong/android"
+)
+
+// Build rules and utilities to generate individual packages/modules/SdkExtensions/proto/classpaths.proto
+// config files based on build configuration to embed into /system and /apex on a device.
+//
+// See `derive_classpath` service that reads the configs at runtime and defines *CLASSPATH variables
+// on the device.
+
+type classpathType int
+
+const (
+ // Matches definition in packages/modules/SdkExtensions/proto/classpaths.proto
+ BOOTCLASSPATH classpathType = iota
+ DEX2OATBOOTCLASSPATH
+ SYSTEMSERVERCLASSPATH
+)
+
+func (c classpathType) String() string {
+ return [...]string{"BOOTCLASSPATH", "DEX2OATBOOTCLASSPATH", "SYSTEMSERVERCLASSPATH"}[c]
+}
+
+type classpathFragmentProperties struct {
+}
+
+// classpathFragment interface is implemented by a module that contributes jars to a *CLASSPATH
+// variables at runtime.
+type classpathFragment interface {
+ android.Module
+
+ classpathFragmentBase() *ClasspathFragmentBase
+}
+
+// ClasspathFragmentBase is meant to be embedded in any module types that implement classpathFragment;
+// such modules are expected to call initClasspathFragment().
+type ClasspathFragmentBase struct {
+ properties classpathFragmentProperties
+
+ outputFilepath android.OutputPath
+ installDirPath android.InstallPath
+}
+
+func (c *ClasspathFragmentBase) classpathFragmentBase() *ClasspathFragmentBase {
+ return c
+}
+
+// Initializes ClasspathFragmentBase struct. Must be called by all modules that include ClasspathFragmentBase.
+func initClasspathFragment(c classpathFragment) {
+ base := c.classpathFragmentBase()
+ c.AddProperties(&base.properties)
+}
+
+// Matches definition of Jar in packages/modules/SdkExtensions/proto/classpaths.proto
+type classpathJar struct {
+ path string
+ classpath classpathType
+ // TODO(satayev): propagate min/max sdk versions for the jars
+ minSdkVersion int32
+ maxSdkVersion int32
+}
+
+func (c *ClasspathFragmentBase) generateAndroidBuildActions(ctx android.ModuleContext) {
+ outputFilename := ctx.ModuleName() + ".pb"
+ c.outputFilepath = android.PathForModuleOut(ctx, outputFilename).OutputPath
+ c.installDirPath = android.PathForModuleInstall(ctx, "etc", "classpaths")
+
+ var jars []classpathJar
+ jars = appendClasspathJar(jars, BOOTCLASSPATH, defaultBootclasspath(ctx)...)
+ jars = appendClasspathJar(jars, DEX2OATBOOTCLASSPATH, defaultBootImageConfig(ctx).getAnyAndroidVariant().dexLocationsDeps...)
+ jars = appendClasspathJar(jars, SYSTEMSERVERCLASSPATH, systemServerClasspath(ctx)...)
+
+ generatedJson := android.PathForModuleOut(ctx, outputFilename+".json")
+ writeClasspathsJson(ctx, generatedJson, jars)
+
+ rule := android.NewRuleBuilder(pctx, ctx)
+ rule.Command().
+ BuiltTool("conv_classpaths_proto").
+ Flag("encode").
+ Flag("--format=json").
+ FlagWithInput("--input=", generatedJson).
+ FlagWithOutput("--output=", c.outputFilepath)
+
+ rule.Build("classpath_fragment", "Compiling "+c.outputFilepath.String())
+}
+
+func writeClasspathsJson(ctx android.ModuleContext, output android.WritablePath, jars []classpathJar) {
+ var content strings.Builder
+ fmt.Fprintf(&content, "{\n")
+ fmt.Fprintf(&content, "\"jars\": [\n")
+ for idx, jar := range jars {
+ fmt.Fprintf(&content, "{\n")
+
+ fmt.Fprintf(&content, "\"relativePath\": \"%s\",\n", jar.path)
+ fmt.Fprintf(&content, "\"classpath\": \"%s\"\n", jar.classpath)
+
+ if idx < len(jars)-1 {
+ fmt.Fprintf(&content, "},\n")
+ } else {
+ fmt.Fprintf(&content, "}\n")
+ }
+ }
+ fmt.Fprintf(&content, "]\n")
+ fmt.Fprintf(&content, "}\n")
+ android.WriteFileRule(ctx, output, content.String())
+}
+
+func appendClasspathJar(slice []classpathJar, classpathType classpathType, paths ...string) (result []classpathJar) {
+ result = append(result, slice...)
+ for _, path := range paths {
+ result = append(result, classpathJar{
+ path: path,
+ classpath: classpathType,
+ })
+ }
+ return
+}
+
+func (c *ClasspathFragmentBase) getAndroidMkEntries() []android.AndroidMkEntries {
+ return []android.AndroidMkEntries{android.AndroidMkEntries{
+ Class: "ETC",
+ OutputFile: android.OptionalPathForPath(c.outputFilepath),
+ ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+ func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+ entries.SetString("LOCAL_MODULE_PATH", c.installDirPath.ToMakePath().String())
+ entries.SetString("LOCAL_INSTALLED_MODULE_STEM", c.outputFilepath.Base())
+ },
+ },
+ }}
+}
diff --git a/java/dex.go b/java/dex.go
index 5c6d41d..7898e9d 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -15,6 +15,7 @@
package java
import (
+ "strconv"
"strings"
"github.com/google/blueprint"
@@ -179,7 +180,7 @@
ctx.PropertyErrorf("min_sdk_version", "%s", err)
}
- flags = append(flags, "--min-api "+effectiveVersion.AsNumberString())
+ flags = append(flags, "--min-api "+strconv.Itoa(effectiveVersion.FinalOrFutureInt()))
return flags
}
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 7137f33..e57c3e9 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -484,7 +484,7 @@
// Now match the apex part of the boot image configuration.
requiredApex := bootjars.Apex(index)
- if requiredApex == "platform" {
+ 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 -1, nil, nil
diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go
index d78651d..73f21d1 100644
--- a/java/dexpreopt_bootjars_test.go
+++ b/java/dexpreopt_bootjars_test.go
@@ -35,6 +35,7 @@
name: "bar",
srcs: ["b.java"],
installable: true,
+ system_ext_specific: true,
}
dex_import {
@@ -47,7 +48,7 @@
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
FixtureWithLastReleaseApis("foo"),
- dexpreopt.FixtureSetBootJars("platform:foo", "platform:bar", "platform:baz"),
+ dexpreopt.FixtureSetBootJars("platform:foo", "system_ext:bar", "platform:baz"),
).RunTestWithBp(t, bp)
dexpreoptBootJars := result.SingletonForTests("dex_bootjars")
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 64b2656..656f5ef 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -26,7 +26,7 @@
// 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.MakeVarsContext) []string {
+func systemServerClasspath(ctx android.PathContext) []string {
return ctx.Config().OnceStringSlice(systemServerClasspathKey, func() []string {
global := dexpreopt.GetGlobalConfig(ctx)
var systemServerClasspathLocations []string
diff --git a/java/droiddoc.go b/java/droiddoc.go
index a0d99a7..01c0f16 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -98,10 +98,6 @@
// names of the output files used in args that will be generated
Out []string
-
- // If set, metalava is sandboxed to only read files explicitly specified on the command
- // line. Defaults to false.
- Sandbox *bool
}
type ApiToCheck struct {
@@ -265,20 +261,20 @@
var _ android.OutputFileProducer = (*Javadoc)(nil)
-func (j *Javadoc) SdkVersion() android.SdkSpec {
- return android.SdkSpecFrom(String(j.properties.Sdk_version))
+func (j *Javadoc) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+ return android.SdkSpecFrom(ctx, String(j.properties.Sdk_version))
}
func (j *Javadoc) SystemModules() string {
return proptools.String(j.properties.System_modules)
}
-func (j *Javadoc) MinSdkVersion() android.SdkSpec {
- return j.SdkVersion()
+func (j *Javadoc) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+ return j.SdkVersion(ctx)
}
-func (j *Javadoc) TargetSdkVersion() android.SdkSpec {
- return j.SdkVersion()
+func (j *Javadoc) TargetSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+ return j.SdkVersion(ctx)
}
func (j *Javadoc) addDeps(ctx android.BottomUpMutatorContext) {
@@ -390,7 +386,7 @@
}
case libTag:
if dep, ok := module.(SdkLibraryDependency); ok {
- deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion())...)
+ deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))...)
} else if ctx.OtherModuleHasProvider(module, JavaInfoProvider) {
dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
deps.classpath = append(deps.classpath, dep.HeaderJars...)
diff --git a/java/droidstubs.go b/java/droidstubs.go
index 3469616..a9e2749 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -383,7 +383,7 @@
func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion javaVersion, srcs android.Paths,
srcJarList android.Path, bootclasspath, classpath classpath, sourcepaths android.Paths,
- implicitsRsp, homeDir android.WritablePath, sandbox bool) *android.RuleBuilderCommand {
+ homeDir android.WritablePath) *android.RuleBuilderCommand {
rule.Command().Text("rm -rf").Flag(homeDir.String())
rule.Command().Text("mkdir -p").Flag(homeDir.String())
@@ -392,39 +392,16 @@
if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_METALAVA") {
rule.Remoteable(android.RemoteRuleSupports{RBE: true})
- if sandbox {
- execStrategy := ctx.Config().GetenvWithDefault("RBE_METALAVA_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
- labels := map[string]string{"type": "tool", "name": "metalava"}
- // TODO: metalava pool rejects these jobs
- pool := ctx.Config().GetenvWithDefault("RBE_METALAVA_POOL", "java16")
- rule.Rewrapper(&remoteexec.REParams{
- Labels: labels,
- ExecStrategy: execStrategy,
- ToolchainInputs: []string{config.JavaCmd(ctx).String()},
- Platform: map[string]string{remoteexec.PoolKey: pool},
- })
- } else {
- execStrategy := remoteexec.LocalExecStrategy
- labels := map[string]string{"type": "compile", "lang": "java", "compiler": "metalava", "shallow": "true"}
- pool := ctx.Config().GetenvWithDefault("RBE_METALAVA_POOL", "metalava")
-
- inputs := []string{
- ctx.Config().HostJavaToolPath(ctx, "metalava").String(),
- homeDir.String(),
- }
- if v := ctx.Config().Getenv("RBE_METALAVA_INPUTS"); v != "" {
- inputs = append(inputs, strings.Split(v, ",")...)
- }
- cmd.Text((&remoteexec.REParams{
- Labels: labels,
- ExecStrategy: execStrategy,
- Inputs: inputs,
- RSPFiles: []string{implicitsRsp.String()},
- ToolchainInputs: []string{config.JavaCmd(ctx).String()},
- Platform: map[string]string{remoteexec.PoolKey: pool},
- EnvironmentVariables: []string{"ANDROID_PREFS_ROOT"},
- }).NoVarTemplate(ctx.Config().RBEWrapper()))
- }
+ execStrategy := ctx.Config().GetenvWithDefault("RBE_METALAVA_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
+ labels := map[string]string{"type": "tool", "name": "metalava"}
+ // TODO: metalava pool rejects these jobs
+ pool := ctx.Config().GetenvWithDefault("RBE_METALAVA_POOL", "java16")
+ rule.Rewrapper(&remoteexec.REParams{
+ Labels: labels,
+ ExecStrategy: execStrategy,
+ ToolchainInputs: []string{config.JavaCmd(ctx).String()},
+ Platform: map[string]string{remoteexec.PoolKey: pool},
+ })
}
cmd.BuiltTool("metalava").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "metalava.jar")).
@@ -435,18 +412,6 @@
FlagWithRspFileInputList("@", android.PathForModuleOut(ctx, "metalava.rsp"), srcs).
FlagWithInput("@", srcJarList)
- if !sandbox {
- if javaHome := ctx.Config().Getenv("ANDROID_JAVA_HOME"); javaHome != "" {
- cmd.Implicit(android.PathForSource(ctx, javaHome))
- }
-
- cmd.FlagWithOutput("--strict-input-files:warn ", android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"violations.txt"))
-
- if implicitsRsp != nil {
- cmd.FlagWithArg("--strict-input-files-exempt ", "@"+implicitsRsp.String())
- }
- }
-
if len(bootclasspath) > 0 {
cmd.FlagWithInputList("-bootclasspath ", bootclasspath.Paths(), ":")
}
@@ -482,12 +447,9 @@
rule := android.NewRuleBuilder(pctx, ctx)
- sandbox := proptools.BoolDefault(d.Javadoc.properties.Sandbox, true)
- if sandbox {
- rule.Sbox(android.PathForModuleOut(ctx, "metalava"),
- android.PathForModuleOut(ctx, "metalava.sbox.textproto")).
- SandboxInputs()
- }
+ rule.Sbox(android.PathForModuleOut(ctx, "metalava"),
+ android.PathForModuleOut(ctx, "metalava.sbox.textproto")).
+ SandboxInputs()
if BoolDefault(d.properties.High_mem, false) {
// This metalava run uses lots of memory, restrict the number of metalava jobs that can run in parallel.
@@ -505,11 +467,9 @@
srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
- implicitsRsp := android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"implicits.rsp")
homeDir := android.PathForModuleOut(ctx, "metalava", "home")
cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList,
- deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths, implicitsRsp, homeDir,
- sandbox)
+ deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths, homeDir)
cmd.Implicits(d.Javadoc.implicits)
d.stubsFlags(ctx, cmd, stubsDir)
@@ -628,22 +588,6 @@
cmd.FlagWithArg("--error-message:compatibility:released ", msg)
}
- if !sandbox {
- // When sandboxing is enabled RuleBuilder tracks all the inputs needed for remote execution.
- // Without it we have to do it manually.
- impRule := android.NewRuleBuilder(pctx, ctx)
- impCmd := impRule.Command()
- // An action that copies the ninja generated rsp file to a new location. This allows us to
- // add a large number of inputs to a file without exceeding bash command length limits (which
- // would happen if we use the WriteFile rule). The cp is needed because RuleBuilder sets the
- // rsp file to be ${output}.rsp.
- impCmd.Text("cp").
- FlagWithRspFileInputList("", android.PathForModuleOut(ctx, "metalava-implicits.rsp"), cmd.GetImplicits()).
- Output(implicitsRsp)
- impRule.Build("implicitsGen", "implicits generation")
- cmd.Implicit(implicitsRsp)
- }
-
if generateStubs {
rule.Command().
BuiltTool("soong_zip").
@@ -675,9 +619,7 @@
}
// TODO(b/183630617): rewrapper doesn't support restat rules
- if !sandbox {
- rule.Restat()
- }
+ // rule.Restat()
zipSyncCleanupCmd(rule, srcJarDir)
diff --git a/java/droidstubs_test.go b/java/droidstubs_test.go
index f8125fb..db664c1 100644
--- a/java/droidstubs_test.go
+++ b/java/droidstubs_test.go
@@ -34,7 +34,6 @@
srcs: ["bar-doc/a.java"],
api_levels_annotations_dirs: ["droiddoc-templates-sdk"],
api_levels_annotations_enabled: true,
- sandbox: false,
}
droidstubs {
@@ -44,7 +43,6 @@
api_levels_annotations_dirs: ["droiddoc-templates-sdk"],
api_levels_annotations_enabled: true,
api_levels_jar_filename: "android.other.jar",
- sandbox: false,
}
`,
map[string][]byte{
@@ -68,13 +66,15 @@
}
for _, c := range testcases {
m := ctx.ModuleForTests(c.moduleName, "android_common")
- metalava := m.Rule("metalava")
- rp := metalava.RuleParams
+ manifest := m.Output("metalava.sbox.textproto")
+ sboxProto := android.RuleBuilderSboxProtoForTests(t, manifest)
expected := "--android-jar-pattern ./%/public/" + c.expectedJarFilename
- if actual := rp.Command; !strings.Contains(actual, expected) {
+ if actual := String(sboxProto.Commands[0].Command); !strings.Contains(actual, expected) {
t.Errorf("For %q, expected metalava argument %q, but was not found %q", c.moduleName, expected, actual)
}
+ metalava := m.Rule("metalava")
+ rp := metalava.RuleParams
if actual := rp.Pool != nil && strings.Contains(rp.Pool.String(), "highmem"); actual != c.high_mem {
t.Errorf("Expected %q high_mem to be %v, was %v", c.moduleName, c.high_mem, actual)
}
@@ -92,7 +92,6 @@
droidstubs {
name: "bar-stubs",
srcs: ["bar-doc/a.java"],
- sandbox: true,
args: "--reference $(location :foo)",
arg_files: [":foo"],
diff --git a/java/hiddenapi.go b/java/hiddenapi.go
index 208ced7..3ecb977 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -111,6 +111,13 @@
var _ hiddenAPIIntf = (*hiddenAPI)(nil)
+// hiddenAPISupportingModule is the interface that is implemented by any module that supports
+// contributing to the hidden API processing.
+type hiddenAPISupportingModule interface {
+ android.Module
+ hiddenAPIIntf
+}
+
// Initialize the hiddenapi structure
func (h *hiddenAPI) initHiddenAPI(ctx android.BaseModuleContext, configurationName string) {
// If hiddenapi processing is disabled treat this as inactive.
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
new file mode 100644
index 0000000..7cf082b
--- /dev/null
+++ b/java/hiddenapi_modular.go
@@ -0,0 +1,219 @@
+// 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"
+)
+
+// Contains support for processing hiddenAPI in a modular fashion.
+
+// HiddenAPIFlagFileProperties contains paths to the flag files that can be used to augment the
+// information obtained from annotations within the source code in order to create the complete set
+// of flags that should be applied to the dex implementation jars on the bootclasspath.
+//
+// Each property contains a list of paths. With the exception of the Unsupported_packages the paths
+// of each property reference a plain text file that contains a java signature per line. The flags
+// for each of those signatures will be updated in a property specific way.
+//
+// The Unsupported_packages property contains a list of paths, each of which is a plain text file
+// with one Java package per line. All members of all classes within that package (but not nested
+// packages) will be updated in a property specific way.
+type HiddenAPIFlagFileProperties struct {
+ // Marks each signature in the referenced files as being unsupported.
+ Unsupported []string `android:"path"`
+
+ // Marks each signature in the referenced files as being unsupported because it has been removed.
+ // Any conflicts with other flags are ignored.
+ Removed []string `android:"path"`
+
+ // Marks each signature in the referenced files as being supported only for targetSdkVersion <= R
+ // and low priority.
+ Max_target_r_low_priority []string `android:"path"`
+
+ // Marks each signature in the referenced files as being supported only for targetSdkVersion <= Q.
+ Max_target_q []string `android:"path"`
+
+ // Marks each signature in the referenced files as being supported only for targetSdkVersion <= P.
+ Max_target_p []string `android:"path"`
+
+ // Marks each signature in the referenced files as being supported only for targetSdkVersion <= O
+ // and low priority. Any conflicts with other flags are ignored.
+ Max_target_o_low_priority []string `android:"path"`
+
+ // Marks each signature in the referenced files as being blocked.
+ Blocked []string `android:"path"`
+
+ // Marks each signature in every package in the referenced files as being unsupported.
+ 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.propertyAccessor(p))
+ info.categoryToPaths[category] = paths
+ }
+ return info
+}
+
+type hiddenAPIFlagFileCategory struct {
+ // propertyName is the name of the property for this category.
+ propertyName string
+
+ // propertyAccessor retrieves the value of the property for this category from the set of
+ // properties.
+ propertyAccessor func(properties *HiddenAPIFlagFileProperties) []string
+
+ // commandMutator adds the appropriate command line options for this category to the supplied
+ // command
+ commandMutator func(command *android.RuleBuilderCommand, path android.Path)
+}
+
+var hiddenAPIFlagFileCategories = []*hiddenAPIFlagFileCategory{
+ // See HiddenAPIFlagFileProperties.Unsupported
+ {
+ propertyName: "unsupported",
+ propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string {
+ return properties.Unsupported
+ },
+ commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
+ command.FlagWithInput("--unsupported ", path)
+ },
+ },
+ // See HiddenAPIFlagFileProperties.Removed
+ {
+ propertyName: "removed",
+ propertyAccessor: 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")
+ },
+ },
+ // See HiddenAPIFlagFileProperties.Max_target_r_low_priority
+ {
+ propertyName: "max_target_r_low_priority",
+ propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string {
+ return properties.Max_target_r_low_priority
+ },
+ commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
+ command.FlagWithInput("--max-target-r ", path).FlagWithArg("--tag ", "lo-prio")
+ },
+ },
+ // See HiddenAPIFlagFileProperties.Max_target_q
+ {
+ propertyName: "max_target_q",
+ propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string {
+ return properties.Max_target_q
+ },
+ commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
+ command.FlagWithInput("--max-target-q ", path)
+ },
+ },
+ // See HiddenAPIFlagFileProperties.Max_target_p
+ {
+ propertyName: "max_target_p",
+ propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string {
+ return properties.Max_target_p
+ },
+ commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
+ command.FlagWithInput("--max-target-p ", path)
+ },
+ },
+ // See HiddenAPIFlagFileProperties.Max_target_o_low_priority
+ {
+ propertyName: "max_target_o_low_priority",
+ propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string {
+ return properties.Max_target_o_low_priority
+ },
+ commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
+ command.FlagWithInput("--max-target-o ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "lo-prio")
+ },
+ },
+ // See HiddenAPIFlagFileProperties.Blocked
+ {
+ propertyName: "blocked",
+ propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string {
+ return properties.Blocked
+ },
+ commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
+ command.FlagWithInput("--blocked ", path)
+ },
+ },
+ // See HiddenAPIFlagFileProperties.Unsupported_packages
+ {
+ propertyName: "unsupported_packages",
+ propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string {
+ return properties.Unsupported_packages
+ },
+ commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
+ command.FlagWithInput("--unsupported ", path).Flag("--packages ")
+ },
+ },
+}
+
+// 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
+}
+
+// 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.
+// 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) {
+ tempPath := android.PathForOutput(ctx, outputPath.Rel()+".tmp")
+ rule := android.NewRuleBuilder(pctx, ctx)
+ command := rule.Command().
+ BuiltTool("generate_hiddenapi_lists").
+ FlagWithInput("--csv ", baseFlagsPath).
+ Inputs(moduleSpecificFlagsPaths).
+ FlagWithOutput("--output ", tempPath)
+
+ // Add the options for the different categories of flag files.
+ for _, category := range hiddenAPIFlagFileCategories {
+ paths := augmentationInfo.categoryToPaths[category]
+ for _, path := range paths {
+ category.commandMutator(command, path)
+ }
+ }
+
+ commitChangeForRestat(rule, tempPath, outputPath)
+
+ rule.Build("hiddenAPIFlagsFile", "hiddenapi flags")
+}
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index 6ad4ff3..ed0b722 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -15,10 +15,7 @@
package java
import (
- "fmt"
-
"android/soong/android"
- "android/soong/genrule"
)
func init() {
@@ -27,8 +24,6 @@
func RegisterHiddenApiSingletonComponents(ctx android.RegistrationContext) {
ctx.RegisterSingletonType("hiddenapi", hiddenAPISingletonFactory)
- ctx.RegisterSingletonType("hiddenapi_index", hiddenAPIIndexSingletonFactory)
- ctx.RegisterModuleType("hiddenapi_flags", hiddenAPIFlagsFactory)
}
var PrepareForTestWithHiddenApiBuildComponents = android.FixtureRegisterWithContext(RegisterHiddenApiSingletonComponents)
@@ -102,11 +97,15 @@
// yet been created.
func hiddenAPISingletonPaths(ctx android.PathContext) hiddenAPISingletonPathsStruct {
return ctx.Config().Once(hiddenAPISingletonPathsKey, func() interface{} {
+ // Make the paths relative to the out/soong/hiddenapi directory instead of to the out/soong/
+ // directory. This ensures that if they are used as java_resources they do not end up in a
+ // hiddenapi directory in the resulting APK.
+ hiddenapiDir := android.PathForOutput(ctx, "hiddenapi")
return hiddenAPISingletonPathsStruct{
- flags: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-flags.csv"),
- index: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-index.csv"),
- metadata: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-unsupported.csv"),
- stubFlags: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-stub-flags.txt"),
+ flags: hiddenapiDir.Join(ctx, "hiddenapi-flags.csv"),
+ index: hiddenapiDir.Join(ctx, "hiddenapi-index.csv"),
+ metadata: hiddenapiDir.Join(ctx, "hiddenapi-unsupported.csv"),
+ stubFlags: hiddenapiDir.Join(ctx, "hiddenapi-stub-flags.txt"),
}
}).(hiddenAPISingletonPathsStruct)
}
@@ -116,7 +115,7 @@
}
type hiddenAPISingleton struct {
- flags, metadata android.Path
+ flags android.Path
}
// hiddenAPI singleton rules
@@ -138,30 +137,25 @@
if ctx.Config().PrebuiltHiddenApiDir(ctx) != "" {
h.flags = 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)
- h.metadata = metadataRule(ctx)
} else {
h.flags = emptyFlagsRule(ctx)
}
}
// Export paths to Make. INTERNAL_PLATFORM_HIDDENAPI_FLAGS is used by Make rules in art/ and cts/.
-// Both paths are used to call dist-for-goals.
func (h *hiddenAPISingleton) MakeVars(ctx android.MakeVarsContext) {
if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
return
}
ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_FLAGS", h.flags.String())
-
- if h.metadata != nil {
- ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_GREYLIST_METADATA", h.metadata.String())
- }
}
// stubFlagsRule creates the rule to build hiddenapi-stub-flags.txt out of dex jars from stub modules and boot image
@@ -186,17 +180,6 @@
// We do not have prebuilts of the core platform api yet
corePlatformStubModules = append(corePlatformStubModules, "legacy.core.platform.api.stubs")
- // Add the android.test.base to the set of stubs only if the android.test.base module is on
- // the boot jars list as the runtime will only enforce hiddenapi access against modules on
- // that list.
- if inList("android.test.base", ctx.Config().BootJars()) {
- if ctx.Config().AlwaysUsePrebuiltSdks() {
- publicStubModules = append(publicStubModules, "sdk_public_current_android.test.base")
- } else {
- publicStubModules = append(publicStubModules, "android.test.base.stubs")
- }
- }
-
// Allow products to define their own stubs for custom product jars that apps can use.
publicStubModules = append(publicStubModules, ctx.Config().ProductHiddenAPIStubs()...)
systemStubModules = append(systemStubModules, ctx.Config().ProductHiddenAPIStubsSystem()...)
@@ -332,63 +315,21 @@
return outputPath
}
-// flagsRule creates a rule to build hiddenapi-flags.csv out of flags.csv files generated for boot image modules and
-// the unsupported API.
-func flagsRule(ctx android.SingletonContext) android.Path {
- var flagsCSV android.Paths
- var combinedRemovedApis android.Path
+func prebuiltIndexRule(ctx android.SingletonContext) {
+ outputPath := hiddenAPISingletonPaths(ctx).index
+ inputPath := android.PathForSource(ctx, ctx.Config().PrebuiltHiddenApiDir(ctx), "hiddenapi-index.csv")
- ctx.VisitAllModules(func(module android.Module) {
- if h, ok := module.(hiddenAPIIntf); ok {
- if csv := h.flagsCSV(); csv != nil {
- flagsCSV = append(flagsCSV, csv)
- }
- } else if g, ok := module.(*genrule.Module); ok {
- if ctx.ModuleName(module) == "combined-removed-dex" {
- if len(g.GeneratedSourceFiles()) != 1 || combinedRemovedApis != nil {
- ctx.Errorf("Expected 1 combined-removed-dex module that generates 1 output file.")
- }
- combinedRemovedApis = g.GeneratedSourceFiles()[0]
- }
- }
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Output: outputPath,
+ Input: inputPath,
})
+}
- if combinedRemovedApis == nil {
- ctx.Errorf("Failed to find combined-removed-dex.")
- }
-
- rule := android.NewRuleBuilder(pctx, ctx)
-
+// 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
- tempPath := android.PathForOutput(ctx, outputPath.Rel()+".tmp")
-
- stubFlags := hiddenAPISingletonPaths(ctx).stubFlags
-
- rule.Command().
- BuiltTool("generate_hiddenapi_lists").
- FlagWithInput("--csv ", stubFlags).
- Inputs(flagsCSV).
- FlagWithInput("--unsupported ",
- android.PathForSource(ctx, "frameworks/base/config/hiddenapi-unsupported.txt")).
- FlagWithInput("--unsupported ", combinedRemovedApis).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "removed").
- FlagWithInput("--max-target-r ",
- android.PathForSource(ctx, "frameworks/base/config/hiddenapi-max-target-r-loprio.txt")).FlagWithArg("--tag ", "lo-prio").
- FlagWithInput("--max-target-q ",
- android.PathForSource(ctx, "frameworks/base/config/hiddenapi-max-target-q.txt")).
- FlagWithInput("--max-target-p ",
- android.PathForSource(ctx, "frameworks/base/config/hiddenapi-max-target-p.txt")).
- FlagWithInput("--max-target-o ", android.PathForSource(
- ctx, "frameworks/base/config/hiddenapi-max-target-o.txt")).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "lo-prio").
- FlagWithInput("--blocked ",
- android.PathForSource(ctx, "frameworks/base/config/hiddenapi-force-blocked.txt")).
- FlagWithInput("--unsupported ", android.PathForSource(
- ctx, "frameworks/base/config/hiddenapi-unsupported-packages.txt")).Flag("--packages ").
- FlagWithOutput("--output ", tempPath)
-
- commitChangeForRestat(rule, tempPath, outputPath)
-
- rule.Build("hiddenAPIFlagsFile", "hiddenapi flags")
-
return outputPath
}
@@ -407,34 +348,6 @@
return outputPath
}
-// metadataRule creates a rule to build hiddenapi-unsupported.csv out of the metadata.csv files generated for boot image
-// modules.
-func metadataRule(ctx android.SingletonContext) android.Path {
- var metadataCSV android.Paths
-
- ctx.VisitAllModules(func(module android.Module) {
- if h, ok := module.(hiddenAPIIntf); ok {
- if csv := h.metadataCSV(); csv != nil {
- metadataCSV = append(metadataCSV, csv)
- }
- }
- })
-
- rule := android.NewRuleBuilder(pctx, ctx)
-
- outputPath := hiddenAPISingletonPaths(ctx).metadata
-
- rule.Command().
- BuiltTool("merge_csv").
- Flag("--key_field signature").
- FlagWithOutput("--output=", outputPath).
- Inputs(metadataCSV)
-
- rule.Build("hiddenAPIGreylistMetadataFile", "hiddenapi greylist metadata")
-
- return outputPath
-}
-
// commitChangeForRestat adds a command to a rule that updates outputPath from tempPath if they are different. It
// also marks the rule as restat and marks the tempPath as a temporary file that should not be considered an output of
// the rule.
@@ -452,105 +365,3 @@
Text("fi").
Text(")")
}
-
-type hiddenAPIFlagsProperties struct {
- // name of the file into which the flags will be copied.
- Filename *string
-}
-
-type hiddenAPIFlags struct {
- android.ModuleBase
-
- properties hiddenAPIFlagsProperties
-
- outputFilePath android.OutputPath
-}
-
-func (h *hiddenAPIFlags) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- filename := String(h.properties.Filename)
-
- inputPath := hiddenAPISingletonPaths(ctx).flags
- h.outputFilePath = android.PathForModuleOut(ctx, filename).OutputPath
-
- // This ensures that outputFilePath has the correct name for others to
- // use, as the source file may have a different name.
- ctx.Build(pctx, android.BuildParams{
- Rule: android.Cp,
- Output: h.outputFilePath,
- Input: inputPath,
- })
-}
-
-func (h *hiddenAPIFlags) OutputFiles(tag string) (android.Paths, error) {
- switch tag {
- case "":
- return android.Paths{h.outputFilePath}, nil
- default:
- return nil, fmt.Errorf("unsupported module reference tag %q", tag)
- }
-}
-
-// hiddenapi-flags provides access to the hiddenapi-flags.csv file generated during the build.
-func hiddenAPIFlagsFactory() android.Module {
- module := &hiddenAPIFlags{}
- module.AddProperties(&module.properties)
- android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
- return module
-}
-
-func hiddenAPIIndexSingletonFactory() android.Singleton {
- return &hiddenAPIIndexSingleton{}
-}
-
-type hiddenAPIIndexSingleton struct {
- index android.Path
-}
-
-func (h *hiddenAPIIndexSingleton) GenerateBuildActions(ctx android.SingletonContext) {
- // Don't run any hiddenapi rules if UNSAFE_DISABLE_HIDDENAPI_FLAGS=true
- if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
- return
- }
-
- if ctx.Config().PrebuiltHiddenApiDir(ctx) != "" {
- outputPath := hiddenAPISingletonPaths(ctx).index
- inputPath := android.PathForSource(ctx, ctx.Config().PrebuiltHiddenApiDir(ctx), "hiddenapi-index.csv")
-
- ctx.Build(pctx, android.BuildParams{
- Rule: android.Cp,
- Output: outputPath,
- Input: inputPath,
- })
-
- h.index = outputPath
- return
- }
-
- indexes := android.Paths{}
- ctx.VisitAllModules(func(module android.Module) {
- if h, ok := module.(hiddenAPIIntf); ok {
- if h.indexCSV() != nil {
- indexes = append(indexes, h.indexCSV())
- }
- }
- })
-
- 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("singleton-merged-hiddenapi-index", "Singleton merged Hidden API index")
-
- h.index = hiddenAPISingletonPaths(ctx).index
-}
-
-func (h *hiddenAPIIndexSingleton) MakeVars(ctx android.MakeVarsContext) {
- if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
- return
- }
-
- ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_INDEX", h.index.String())
-}
diff --git a/java/hiddenapi_singleton_test.go b/java/hiddenapi_singleton_test.go
index 5c449e5..5ea9a5b 100644
--- a/java/hiddenapi_singleton_test.go
+++ b/java/hiddenapi_singleton_test.go
@@ -23,12 +23,6 @@
"github.com/google/blueprint/proptools"
)
-func fixtureSetBootJarsProductVariable(bootJars ...string) android.FixturePreparer {
- return android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
- variables.BootJars = android.CreateTestConfiguredJarList(bootJars)
- })
-}
-
func fixtureSetPrebuiltHiddenApiDirProductVariable(prebuiltHiddenApiDir *string) android.FixturePreparer {
return android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
variables.PrebuiltHiddenApiDir = prebuiltHiddenApiDir
@@ -41,7 +35,7 @@
func TestHiddenAPISingleton(t *testing.T) {
result := android.GroupFixturePreparers(
hiddenApiFixtureFactory,
- fixtureSetBootJarsProductVariable("platform:foo"),
+ FixtureConfigureBootJars("platform:foo"),
).RunTestWithBp(t, `
java_library {
name: "foo",
@@ -56,61 +50,6 @@
android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, want)
}
-func TestHiddenAPIIndexSingleton(t *testing.T) {
- result := android.GroupFixturePreparers(
- hiddenApiFixtureFactory,
- PrepareForTestWithJavaSdkLibraryFiles,
- FixtureWithLastReleaseApis("bar"),
- fixtureSetBootJarsProductVariable("platform:foo", "platform:bar"),
- ).RunTestWithBp(t, `
- java_library {
- name: "foo",
- srcs: ["a.java"],
- compile_dex: true,
-
- hiddenapi_additional_annotations: [
- "foo-hiddenapi-annotations",
- ],
- }
-
- java_library {
- name: "foo-hiddenapi-annotations",
- srcs: ["a.java"],
- compile_dex: true,
- }
-
- java_import {
- name: "foo",
- jars: ["a.jar"],
- compile_dex: true,
- prefer: false,
- }
-
- java_sdk_library {
- name: "bar",
- srcs: ["a.java"],
- compile_dex: true,
- }
- `)
-
- hiddenAPIIndex := result.SingletonForTests("hiddenapi_index")
- indexRule := hiddenAPIIndex.Rule("singleton-merged-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")
- CheckHiddenAPIRuleInputs(t, `
-.intermediates/foo-hiddenapi-annotations/android_common/javac/foo-hiddenapi-annotations.jar
-.intermediates/foo/android_common/javac/foo.jar
-`, indexParams)
-}
-
func TestHiddenAPISingletonWithSourceAndPrebuiltPreferredButNoDex(t *testing.T) {
expectedErrorMessage :=
"hiddenapi has determined that the source module \"foo\" should be ignored as it has been" +
@@ -119,7 +58,7 @@
android.GroupFixturePreparers(
hiddenApiFixtureFactory,
- fixtureSetBootJarsProductVariable("platform:foo"),
+ FixtureConfigureBootJars("platform:foo"),
).ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(expectedErrorMessage)).
RunTestWithBp(t, `
java_library {
@@ -139,7 +78,7 @@
func TestHiddenAPISingletonWithPrebuilt(t *testing.T) {
result := android.GroupFixturePreparers(
hiddenApiFixtureFactory,
- fixtureSetBootJarsProductVariable("platform:foo"),
+ FixtureConfigureBootJars("platform:foo"),
).RunTestWithBp(t, `
java_import {
name: "foo",
@@ -157,7 +96,7 @@
func TestHiddenAPISingletonWithPrebuiltUseSource(t *testing.T) {
result := android.GroupFixturePreparers(
hiddenApiFixtureFactory,
- fixtureSetBootJarsProductVariable("platform:foo"),
+ FixtureConfigureBootJars("platform:foo"),
).RunTestWithBp(t, `
java_library {
name: "foo",
@@ -185,7 +124,7 @@
func TestHiddenAPISingletonWithPrebuiltOverrideSource(t *testing.T) {
result := android.GroupFixturePreparers(
hiddenApiFixtureFactory,
- fixtureSetBootJarsProductVariable("platform:foo"),
+ FixtureConfigureBootJars("platform:foo"),
).RunTestWithBp(t, `
java_library {
name: "foo",
@@ -295,7 +234,7 @@
result := android.GroupFixturePreparers(
hiddenApiFixtureFactory,
- fixtureSetBootJarsProductVariable("platform:foo"),
+ FixtureConfigureBootJars("platform:foo"),
fixtureSetPrebuiltHiddenApiDirProductVariable(&prebuiltHiddenApiDir),
).RunTestWithBp(t, `
java_import {
diff --git a/java/java.go b/java/java.go
index 5fe8814..ee4f2eb 100644
--- a/java/java.go
+++ b/java/java.go
@@ -356,7 +356,7 @@
if javaVersion != "" {
return normalizeJavaVersion(ctx, javaVersion)
} else if ctx.Device() {
- return defaultJavaLanguageVersion(ctx, sdkContext.SdkVersion())
+ return defaultJavaLanguageVersion(ctx, sdkContext.SdkVersion(ctx))
} else {
return JAVA_VERSION_9
}
@@ -463,6 +463,9 @@
// 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)
+
apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
if !apexInfo.IsForPlatform() {
j.hideApexVariantFromMake = true
@@ -1130,33 +1133,28 @@
exportAidlIncludeDirs android.Paths
hideApexVariantFromMake bool
+
+ sdkVersion android.SdkSpec
+ minSdkVersion android.SdkSpec
}
-func (j *Import) SdkVersion() android.SdkSpec {
- return android.SdkSpecFrom(String(j.properties.Sdk_version))
-}
-
-func (j *Import) makeSdkVersion() string {
- return j.SdkVersion().Raw
+func (j *Import) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+ return android.SdkSpecFrom(ctx, String(j.properties.Sdk_version))
}
func (j *Import) SystemModules() string {
return "none"
}
-func (j *Import) MinSdkVersion() android.SdkSpec {
+func (j *Import) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
if j.properties.Min_sdk_version != nil {
- return android.SdkSpecFrom(*j.properties.Min_sdk_version)
+ return android.SdkSpecFrom(ctx, *j.properties.Min_sdk_version)
}
- return j.SdkVersion()
+ return j.SdkVersion(ctx)
}
-func (j *Import) TargetSdkVersion() android.SdkSpec {
- return j.SdkVersion()
-}
-
-func (j *Import) MinSdkVersionString() string {
- return j.MinSdkVersion().Version.String()
+func (j *Import) TargetSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+ return j.SdkVersion(ctx)
}
func (j *Import) Prebuilt() *android.Prebuilt {
@@ -1192,6 +1190,9 @@
}
func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ j.sdkVersion = j.SdkVersion(ctx)
+ j.minSdkVersion = j.MinSdkVersion(ctx)
+
// Initialize the hiddenapi structure.
j.initHiddenAPI(ctx, j.BaseModuleName())
@@ -1230,7 +1231,7 @@
} else if dep, ok := module.(SdkLibraryDependency); ok {
switch tag {
case libTag:
- flags.classpath = append(flags.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion())...)
+ flags.classpath = append(flags.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))...)
}
}
@@ -1291,7 +1292,7 @@
j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex
var dexOutputFile android.OutputPath
- dexOutputFile = j.dexer.compileDex(ctx, flags, j.MinSdkVersion(), outputFile, jarName)
+ dexOutputFile = j.dexer.compileDex(ctx, flags, j.MinSdkVersion(ctx), outputFile, jarName)
if ctx.Failed() {
return
}
@@ -1359,7 +1360,7 @@
// Implements android.ApexModule
func (j *Import) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
sdkVersion android.ApiLevel) error {
- sdkSpec := j.MinSdkVersion()
+ sdkSpec := j.MinSdkVersion(ctx)
if !sdkSpec.Specified() {
return fmt.Errorf("min_sdk_version is not specified")
}
@@ -1370,7 +1371,7 @@
if err != nil {
return err
}
- if ver.ApiLevel(ctx).GreaterThan(sdkVersion) {
+ if ver.GreaterThan(sdkVersion) {
return fmt.Errorf("newer SDK(%v)", ver)
}
return nil
diff --git a/java/java_test.go b/java/java_test.go
index fdf7579..0523458 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -1261,6 +1261,14 @@
if !strings.Contains(*sboxProto.Commands[0].Command, "--baseline mybaseline.xml") {
t.Error("did not use the correct file for baseline")
}
+
+ if !strings.Contains(*sboxProto.Commands[0].Command, "--error_check NewApi") {
+ t.Error("should check NewApi errors")
+ }
+
+ if !strings.Contains(*sboxProto.Commands[0].Command, "--error_check SomeCheck") {
+ t.Error("should combine NewApi errors with SomeCheck errors")
+ }
}
func TestGeneratedSources(t *testing.T) {
diff --git a/java/lint.go b/java/lint.go
index 475e8dc..aa308e6 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -57,24 +57,25 @@
}
type linter struct {
- name string
- manifest android.Path
- mergedManifest android.Path
- srcs android.Paths
- srcJars android.Paths
- resources android.Paths
- classpath android.Paths
- classes android.Path
- extraLintCheckJars android.Paths
- test bool
- library bool
- minSdkVersion string
- targetSdkVersion string
- compileSdkVersion string
- javaLanguageLevel string
- kotlinLanguageLevel string
- outputs lintOutputs
- properties LintProperties
+ name string
+ manifest android.Path
+ mergedManifest android.Path
+ srcs android.Paths
+ srcJars android.Paths
+ resources android.Paths
+ classpath android.Paths
+ classes android.Path
+ extraLintCheckJars android.Paths
+ test bool
+ library bool
+ minSdkVersion string
+ targetSdkVersion string
+ compileSdkVersion string
+ javaLanguageLevel string
+ kotlinLanguageLevel string
+ outputs lintOutputs
+ properties LintProperties
+ extraMainlineLintErrors []string
reports android.Paths
@@ -246,6 +247,7 @@
cmd.FlagWithInput("@",
android.PathForSource(ctx, "build/soong/java/lint_defaults.txt"))
+ cmd.FlagForEachArg("--error_check ", l.extraMainlineLintErrors)
cmd.FlagForEachArg("--disable_check ", l.properties.Lint.Disabled_checks)
cmd.FlagForEachArg("--warning_check ", l.properties.Lint.Warning_checks)
cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks)
@@ -282,6 +284,10 @@
return
}
+ if l.minSdkVersion != l.compileSdkVersion {
+ l.extraMainlineLintErrors = append(l.extraMainlineLintErrors, "NewApi")
+ }
+
extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag)
for _, extraLintCheckModule := range extraLintCheckModules {
if ctx.OtherModuleHasProvider(extraLintCheckModule, JavaInfoProvider) {
@@ -347,7 +353,7 @@
cmd := rule.Command()
- cmd.Flag("JAVA_OPTS=-Xmx3072m").
+ cmd.Flag(`JAVA_OPTS="-Xmx3072m --add-opens java.base/java.util=ALL-UNNAMED"`).
FlagWithArg("ANDROID_SDK_HOME=", lintPaths.homeDir.String()).
FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath).
FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath)
@@ -392,6 +398,9 @@
rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
+ // The HTML output contains a date, remove it to make the output deterministic.
+ rule.Command().Text(`sed -i.tmp -e 's|Check performed at .*\(</nav>\)|\1|'`).Output(html)
+
rule.Build("lint", "lint")
l.outputs = lintOutputs{
diff --git a/java/lint_defaults.txt b/java/lint_defaults.txt
index 0786b7c..2de05b0 100644
--- a/java/lint_defaults.txt
+++ b/java/lint_defaults.txt
@@ -76,3 +76,5 @@
# TODO(b/158390965): remove this when lint doesn't crash
--disable_check HardcodedDebugMode
+
+--warning_check QueryAllPackagesPermission
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index 5507077..cb8ad68 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -15,8 +15,12 @@
package java
import (
+ "fmt"
+
"android/soong/android"
"android/soong/dexpreopt"
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
)
func init() {
@@ -25,18 +29,116 @@
func registerPlatformBootclasspathBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("platform_bootclasspath", platformBootclasspathFactory)
+
+ ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("platform_bootclasspath_deps", platformBootclasspathDepsMutator)
+ })
}
+type platformBootclasspathDependencyTag struct {
+ blueprint.BaseDependencyTag
+
+ name string
+}
+
+// Avoid having to make platform bootclasspath content visible to the platform bootclasspath.
+//
+// This is a temporary workaround to make it easier to migrate to platform bootclasspath with proper
+// dependencies.
+// TODO(b/177892522): Remove this and add needed visibility.
+func (t platformBootclasspathDependencyTag) ExcludeFromVisibilityEnforcement() {
+}
+
+// The tag used for the dependency between the platform bootclasspath and any configured boot jars.
+var platformBootclasspathModuleDepTag = platformBootclasspathDependencyTag{name: "module"}
+
+// The tag used for the dependency between the platform bootclasspath and bootclasspath_fragments.
+var platformBootclasspathFragmentDepTag = platformBootclasspathDependencyTag{name: "fragment"}
+
+var _ android.ExcludeFromVisibilityEnforcementTag = platformBootclasspathDependencyTag{}
+
type platformBootclasspathModule struct {
android.ModuleBase
+ ClasspathFragmentBase
+
+ properties platformBootclasspathProperties
+
+ // The apex:module pairs obtained from the configured modules.
+ //
+ // Currently only for testing.
+ configuredModules []android.Module
+
+ // The apex:module pairs obtained from the fragments.
+ //
+ // Currently only for testing.
+ fragments []android.Module
+
+ // Path to the monolithic hiddenapi-flags.csv file.
+ hiddenAPIFlagsCSV android.OutputPath
+
+ // Path to the monolithic hiddenapi-index.csv file.
+ hiddenAPIIndexCSV android.OutputPath
+
+ // Path to the monolithic hiddenapi-unsupported.csv file.
+ hiddenAPIMetadataCSV android.OutputPath
+}
+
+// ApexVariantReference specifies a particular apex variant of a module.
+type ApexVariantReference struct {
+ // The name of the module apex variant, i.e. the apex containing the module variant.
+ //
+ // If this is not specified then it defaults to "platform" which will cause a dependency to be
+ // added to the module's platform variant.
+ Apex *string
+
+ // The name of the module.
+ Module *string
+}
+
+type platformBootclasspathProperties struct {
+ // The names of the bootclasspath_fragment modules that form part of this
+ // platform_bootclasspath.
+ Fragments []ApexVariantReference
+
+ Hidden_api HiddenAPIFlagFileProperties
}
func platformBootclasspathFactory() android.Module {
m := &platformBootclasspathModule{}
+ m.AddProperties(&m.properties)
+ // TODO(satayev): split systemserver and apex jars into separate configs.
+ initClasspathFragment(m)
android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
return m
}
+var _ android.OutputFileProducer = (*platformBootclasspathModule)(nil)
+
+func (b *platformBootclasspathModule) AndroidMkEntries() (entries []android.AndroidMkEntries) {
+ entries = append(entries, android.AndroidMkEntries{
+ Class: "FAKE",
+ // Need at least one output file in order for this to take effect.
+ OutputFile: android.OptionalPathForPath(b.hiddenAPIFlagsCSV),
+ Include: "$(BUILD_PHONY_PACKAGE)",
+ })
+ entries = append(entries, b.classpathFragmentBase().getAndroidMkEntries()...)
+ return
+}
+
+// Make the hidden API files available from the platform-bootclasspath module.
+func (b *platformBootclasspathModule) OutputFiles(tag string) (android.Paths, error) {
+ switch tag {
+ case "hiddenapi-flags.csv":
+ return android.Paths{b.hiddenAPIFlagsCSV}, nil
+ case "hiddenapi-index.csv":
+ return android.Paths{b.hiddenAPIIndexCSV}, nil
+ case "hiddenapi-metadata.csv":
+ return android.Paths{b.hiddenAPIMetadataCSV}, nil
+ }
+
+ return nil, fmt.Errorf("unknown tag %s", tag)
+}
+
func (b *platformBootclasspathModule) DepsMutator(ctx android.BottomUpMutatorContext) {
if SkipDexpreoptBootJars(ctx) {
return
@@ -47,7 +149,117 @@
dexpreopt.RegisterToolDeps(ctx)
}
+func platformBootclasspathDepsMutator(ctx android.BottomUpMutatorContext) {
+ m := ctx.Module()
+ if p, ok := m.(*platformBootclasspathModule); ok {
+ // Add dependencies on all the modules configured in the "art" boot image.
+ artImageConfig := genBootImageConfigs(ctx)[artBootImageName]
+ addDependenciesOntoBootImageModules(ctx, artImageConfig.modules)
+
+ // Add dependencies on all the modules configured in the "boot" boot image. That does not
+ // include modules configured in the "art" boot image.
+ bootImageConfig := p.getImageConfig(ctx)
+ addDependenciesOntoBootImageModules(ctx, bootImageConfig.modules)
+
+ // Add dependencies on all the updatable modules.
+ updatableModules := dexpreopt.GetGlobalConfig(ctx).UpdatableBootJars
+ addDependenciesOntoBootImageModules(ctx, updatableModules)
+
+ // Add dependencies on all the fragments.
+ addDependencyOntoApexVariants(ctx, "fragments", p.properties.Fragments, platformBootclasspathFragmentDepTag)
+ }
+}
+
+func addDependencyOntoApexVariants(ctx android.BottomUpMutatorContext, propertyName string, refs []ApexVariantReference, tag blueprint.DependencyTag) {
+ for i, ref := range refs {
+ apex := proptools.StringDefault(ref.Apex, "platform")
+
+ if ref.Module == nil {
+ ctx.PropertyErrorf(propertyName, "missing module name at position %d", i)
+ continue
+ }
+ name := proptools.String(ref.Module)
+
+ addDependencyOntoApexModulePair(ctx, apex, name, tag)
+ }
+}
+
+func addDependencyOntoApexModulePair(ctx android.BottomUpMutatorContext, apex string, name string, tag blueprint.DependencyTag) {
+ var variations []blueprint.Variation
+ if apex != "platform" {
+ // Pick the correct apex variant.
+ variations = []blueprint.Variation{
+ {Mutator: "apex", Variation: apex},
+ }
+ }
+
+ addedDep := false
+ if ctx.OtherModuleDependencyVariantExists(variations, name) {
+ ctx.AddFarVariationDependencies(variations, tag, name)
+ addedDep = true
+ }
+
+ // Add a dependency on the prebuilt module if it exists.
+ prebuiltName := android.PrebuiltNameFromSource(name)
+ if ctx.OtherModuleDependencyVariantExists(variations, prebuiltName) {
+ ctx.AddVariationDependencies(variations, tag, prebuiltName)
+ addedDep = true
+ }
+
+ // If no appropriate variant existing for this, so no dependency could be added, then it is an
+ // error, unless missing dependencies are allowed. The simplest way to handle that is to add a
+ // dependency that will not be satisfied and the default behavior will handle it.
+ if !addedDep {
+ // Add dependency on the unprefixed (i.e. source or renamed prebuilt) module which we know does
+ // not exist. The resulting error message will contain useful information about the available
+ // variants.
+ reportMissingVariationDependency(ctx, variations, name)
+
+ // Add dependency on the missing prefixed prebuilt variant too if a module with that name exists
+ // so that information about its available variants will be reported too.
+ if ctx.OtherModuleExists(prebuiltName) {
+ reportMissingVariationDependency(ctx, variations, prebuiltName)
+ }
+ }
+}
+
+// reportMissingVariationDependency intentionally adds a dependency on a missing variation in order
+// to generate an appropriate error message with information about the available variations.
+func reportMissingVariationDependency(ctx android.BottomUpMutatorContext, variations []blueprint.Variation, name string) {
+ modules := ctx.AddFarVariationDependencies(variations, nil, name)
+ if len(modules) != 1 {
+ panic(fmt.Errorf("Internal Error: expected one module, found %d", len(modules)))
+ return
+ }
+ if modules[0] != nil {
+ panic(fmt.Errorf("Internal Error: expected module to be missing but was found: %q", modules[0]))
+ return
+ }
+}
+
+func addDependenciesOntoBootImageModules(ctx android.BottomUpMutatorContext, modules android.ConfiguredJarList) {
+ for i := 0; i < modules.Len(); i++ {
+ apex := modules.Apex(i)
+ name := modules.Jar(i)
+
+ addDependencyOntoApexModulePair(ctx, apex, name, platformBootclasspathModuleDepTag)
+ }
+}
+
func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ b.classpathFragmentBase().generateAndroidBuildActions(ctx)
+
+ ctx.VisitDirectDepsIf(isActiveModule, func(module android.Module) {
+ tag := ctx.OtherModuleDependencyTag(module)
+ if tag == platformBootclasspathModuleDepTag {
+ b.configuredModules = append(b.configuredModules, module)
+ } else if tag == platformBootclasspathFragmentDepTag {
+ b.fragments = append(b.fragments, module)
+ }
+ })
+
+ b.generateHiddenAPIBuildActions(ctx, b.configuredModules)
+
// Nothing to do if skipping the dexpreopt of boot image jars.
if SkipDexpreoptBootJars(ctx) {
return
@@ -72,3 +284,101 @@
func (b *platformBootclasspathModule) getImageConfig(ctx android.EarlyModuleContext) *bootImageConfig {
return defaultBootImageConfig(ctx)
}
+
+// generateHiddenAPIBuildActions generates all the hidden API related build rules.
+func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, modules []android.Module) {
+
+ // Save the paths to the monolithic files for retrieval via OutputFiles().
+ b.hiddenAPIFlagsCSV = hiddenAPISingletonPaths(ctx).flags
+ b.hiddenAPIIndexCSV = hiddenAPISingletonPaths(ctx).index
+ b.hiddenAPIMetadataCSV = hiddenAPISingletonPaths(ctx).metadata
+
+ // Don't run any hiddenapi rules if UNSAFE_DISABLE_HIDDENAPI_FLAGS=true. This is a performance
+ // optimization that can be used to reduce the incremental build time but as its name suggests it
+ // can be unsafe to use, e.g. when the changes affect anything that goes on the bootclasspath.
+ if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
+ paths := android.OutputPaths{b.hiddenAPIFlagsCSV, b.hiddenAPIIndexCSV, b.hiddenAPIMetadataCSV}
+ for _, path := range paths {
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Touch,
+ Output: path,
+ })
+ }
+ return
+ }
+
+ hiddenAPISupportingModules := []hiddenAPISupportingModule{}
+ for _, module := range modules {
+ if h, ok := module.(hiddenAPISupportingModule); ok {
+ if h.bootDexJar() == nil {
+ ctx.ModuleErrorf("module %s does not provide a bootDexJar file", module)
+ }
+ if h.flagsCSV() == nil {
+ ctx.ModuleErrorf("module %s does not provide a flagsCSV file", module)
+ }
+ if h.indexCSV() == nil {
+ ctx.ModuleErrorf("module %s does not provide an indexCSV file", module)
+ }
+ if h.metadataCSV() == nil {
+ ctx.ModuleErrorf("module %s does not provide a metadataCSV file", module)
+ }
+
+ if ctx.Failed() {
+ continue
+ }
+
+ hiddenAPISupportingModules = append(hiddenAPISupportingModules, h)
+ } else {
+ ctx.ModuleErrorf("module %s of type %s does not support hidden API processing", module, ctx.OtherModuleType(module))
+ }
+ }
+
+ moduleSpecificFlagsPaths := android.Paths{}
+ for _, module := range hiddenAPISupportingModules {
+ moduleSpecificFlagsPaths = append(moduleSpecificFlagsPaths, module.flagsCSV())
+ }
+
+ augmentationInfo := b.properties.Hidden_api.hiddenAPIFlagFileInfo(ctx)
+
+ outputPath := hiddenAPISingletonPaths(ctx).flags
+ baseFlagsPath := hiddenAPISingletonPaths(ctx).stubFlags
+ ruleToGenerateHiddenApiFlags(ctx, outputPath, baseFlagsPath, moduleSpecificFlagsPaths, augmentationInfo)
+
+ b.generateHiddenAPIIndexRules(ctx, hiddenAPISupportingModules)
+ b.generatedHiddenAPIMetadataRules(ctx, hiddenAPISupportingModules)
+}
+
+func (b *platformBootclasspathModule) generateHiddenAPIIndexRules(ctx android.ModuleContext, modules []hiddenAPISupportingModule) {
+ indexes := android.Paths{}
+ for _, module := range modules {
+ indexes = append(indexes, module.indexCSV())
+ }
+
+ 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)
+
+ rule.Build("platform-bootclasspath-monolithic-hiddenapi-metadata", "monolithic hidden API metadata")
+}
diff --git a/java/platform_bootclasspath_test.go b/java/platform_bootclasspath_test.go
index 1c81cfd..e51b049 100644
--- a/java/platform_bootclasspath_test.go
+++ b/java/platform_bootclasspath_test.go
@@ -29,10 +29,288 @@
)
func TestPlatformBootclasspath(t *testing.T) {
- prepareForTestWithPlatformBootclasspath.
- RunTestWithBp(t, `
+ preparer := android.GroupFixturePreparers(
+ prepareForTestWithPlatformBootclasspath,
+ FixtureConfigureBootJars("platform:foo", "platform:bar"),
+ android.FixtureWithRootAndroidBp(`
platform_bootclasspath {
name: "platform-bootclasspath",
}
- `)
+
+ java_library {
+ name: "bar",
+ srcs: ["a.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ compile_dex: true,
+ }
+ `),
+ )
+
+ var addSourceBootclassPathModule = android.FixtureAddTextFile("source/Android.bp", `
+ java_library {
+ name: "foo",
+ srcs: ["a.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ compile_dex: true,
+ }
+ `)
+
+ var addPrebuiltBootclassPathModule = android.FixtureAddTextFile("prebuilt/Android.bp", `
+ java_import {
+ name: "foo",
+ jars: ["a.jar"],
+ compile_dex: true,
+ prefer: false,
+ }
+ `)
+
+ var addPrebuiltPreferredBootclassPathModule = android.FixtureAddTextFile("prebuilt/Android.bp", `
+ java_import {
+ name: "foo",
+ jars: ["a.jar"],
+ compile_dex: true,
+ prefer: true,
+ }
+ `)
+
+ t.Run("missing", func(t *testing.T) {
+ preparer.
+ ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`"platform-bootclasspath" depends on undefined module "foo"`)).
+ RunTest(t)
+ })
+
+ t.Run("source", func(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ preparer,
+ addSourceBootclassPathModule,
+ ).RunTest(t)
+
+ CheckPlatformBootclasspathModules(t, result, "platform-bootclasspath", []string{
+ "platform:foo",
+ "platform:bar",
+ })
+ })
+
+ t.Run("prebuilt", func(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ preparer,
+ addPrebuiltBootclassPathModule,
+ ).RunTest(t)
+
+ CheckPlatformBootclasspathModules(t, result, "platform-bootclasspath", []string{
+ "platform:prebuilt_foo",
+ "platform:bar",
+ })
+ })
+
+ t.Run("source+prebuilt - source preferred", func(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ preparer,
+ addSourceBootclassPathModule,
+ addPrebuiltBootclassPathModule,
+ ).RunTest(t)
+
+ CheckPlatformBootclasspathModules(t, result, "platform-bootclasspath", []string{
+ "platform:foo",
+ "platform:bar",
+ })
+ })
+
+ t.Run("source+prebuilt - prebuilt preferred", func(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ preparer,
+ addSourceBootclassPathModule,
+ addPrebuiltPreferredBootclassPathModule,
+ ).RunTest(t)
+
+ CheckPlatformBootclasspathModules(t, result, "platform-bootclasspath", []string{
+ "platform:prebuilt_foo",
+ "platform:bar",
+ })
+ })
+}
+
+func TestPlatformBootclasspathVariant(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForTestWithPlatformBootclasspath,
+ android.FixtureWithRootAndroidBp(`
+ platform_bootclasspath {
+ name: "platform-bootclasspath",
+ }
+ `),
+ ).RunTest(t)
+
+ variants := result.ModuleVariantsForTests("platform-bootclasspath")
+ android.AssertIntEquals(t, "expect 1 variant", 1, len(variants))
+}
+
+func TestPlatformBootclasspath_ClasspathFragmentPaths(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForTestWithPlatformBootclasspath,
+ android.FixtureWithRootAndroidBp(`
+ platform_bootclasspath {
+ name: "platform-bootclasspath",
+ }
+ `),
+ ).RunTest(t)
+
+ p := result.Module("platform-bootclasspath", "android_common").(*platformBootclasspathModule)
+ android.AssertStringEquals(t, "output filepath", p.Name()+".pb", p.ClasspathFragmentBase.outputFilepath.Base())
+ android.AssertPathRelativeToTopEquals(t, "install filepath", "out/soong/target/product/test_device/system/etc/classpaths", p.ClasspathFragmentBase.installDirPath)
+}
+
+func TestPlatformBootclasspathModule_AndroidMkEntries(t *testing.T) {
+ preparer := android.GroupFixturePreparers(
+ prepareForTestWithPlatformBootclasspath,
+ android.FixtureWithRootAndroidBp(`
+ platform_bootclasspath {
+ name: "platform-bootclasspath",
+ }
+ `),
+ )
+
+ t.Run("AndroidMkEntries", func(t *testing.T) {
+ result := preparer.RunTest(t)
+
+ p := result.Module("platform-bootclasspath", "android_common").(*platformBootclasspathModule)
+
+ entries := android.AndroidMkEntriesForTest(t, result.TestContext, p)
+ android.AssertIntEquals(t, "AndroidMkEntries count", 2, len(entries))
+ })
+
+ t.Run("hiddenapi-flags-entry", func(t *testing.T) {
+ result := preparer.RunTest(t)
+
+ p := result.Module("platform-bootclasspath", "android_common").(*platformBootclasspathModule)
+
+ entries := android.AndroidMkEntriesForTest(t, result.TestContext, p)
+ got := entries[0].OutputFile
+ android.AssertBoolEquals(t, "valid output path", true, got.Valid())
+ android.AssertSame(t, "output filepath", p.hiddenAPIFlagsCSV, got.Path())
+ })
+
+ t.Run("classpath-fragment-entry", func(t *testing.T) {
+ result := preparer.RunTest(t)
+
+ want := map[string][]string{
+ "LOCAL_MODULE": {"platform-bootclasspath"},
+ "LOCAL_MODULE_CLASS": {"ETC"},
+ "LOCAL_INSTALLED_MODULE_STEM": {"platform-bootclasspath.pb"},
+ // Output and Install paths are tested separately in TestPlatformBootclasspath_ClasspathFragmentPaths
+ }
+
+ p := result.Module("platform-bootclasspath", "android_common").(*platformBootclasspathModule)
+
+ entries := android.AndroidMkEntriesForTest(t, result.TestContext, p)
+ got := entries[1]
+ for k, expectedValue := range want {
+ if value, ok := got.EntryMap[k]; ok {
+ android.AssertDeepEquals(t, k, expectedValue, value)
+ } else {
+ t.Errorf("No %s defined, saw %q", k, got.EntryMap)
+ }
+ }
+ })
+}
+
+func TestPlatformBootclasspath_Dist(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForTestWithPlatformBootclasspath,
+ FixtureConfigureBootJars("platform:foo", "platform:bar"),
+ android.PrepareForTestWithAndroidMk,
+ android.FixtureWithRootAndroidBp(`
+ platform_bootclasspath {
+ name: "platform-bootclasspath",
+ dists: [
+ {
+ targets: ["droidcore"],
+ tag: "hiddenapi-flags.csv",
+ },
+ ],
+ }
+
+ java_library {
+ name: "bar",
+ srcs: ["a.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ compile_dex: true,
+ }
+
+ java_library {
+ name: "foo",
+ srcs: ["a.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ compile_dex: true,
+ }
+ `),
+ ).RunTest(t)
+
+ platformBootclasspath := result.Module("platform-bootclasspath", "android_common").(*platformBootclasspathModule)
+ entries := android.AndroidMkEntriesForTest(t, result.TestContext, platformBootclasspath)
+ goals := entries[0].GetDistForGoals(platformBootclasspath)
+ android.AssertStringEquals(t, "platform dist goals phony", ".PHONY: droidcore\n", goals[0])
+ android.AssertStringEquals(t, "platform dist goals call", "$(call dist-for-goals,droidcore,out/soong/hiddenapi/hiddenapi-flags.csv:hiddenapi-flags.csv)\n", android.StringRelativeToTop(result.Config, goals[1]))
+}
+
+func TestPlatformBootclasspath_HiddenAPIMonolithicFiles(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ hiddenApiFixtureFactory,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("bar"),
+ FixtureConfigureBootJars("platform:foo", "platform:bar"),
+ ).RunTestWithBp(t, `
+ java_library {
+ name: "foo",
+ srcs: ["a.java"],
+ compile_dex: true,
+
+ hiddenapi_additional_annotations: [
+ "foo-hiddenapi-annotations",
+ ],
+ }
+
+ java_library {
+ name: "foo-hiddenapi-annotations",
+ srcs: ["a.java"],
+ compile_dex: true,
+ }
+
+ java_import {
+ name: "foo",
+ jars: ["a.jar"],
+ compile_dex: true,
+ prefer: false,
+ }
+
+ java_sdk_library {
+ name: "bar",
+ srcs: ["a.java"],
+ compile_dex: true,
+ }
+
+ platform_bootclasspath {
+ name: "myplatform-bootclasspath",
+ }
+ `)
+
+ 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")
+ CheckHiddenAPIRuleInputs(t, `
+.intermediates/foo-hiddenapi-annotations/android_common/javac/foo-hiddenapi-annotations.jar
+.intermediates/foo/android_common/javac/foo.jar
+`, indexParams)
}
diff --git a/java/platform_compat_config.go b/java/platform_compat_config.go
index c3d13ae..edfa146 100644
--- a/java/platform_compat_config.go
+++ b/java/platform_compat_config.go
@@ -232,15 +232,7 @@
}
}
- // A prebuilt module should only be used when it is preferred.
- if pi, ok := module.(android.PrebuiltInterface); ok {
- if p := pi.Prebuilt(); p != nil {
- return p.UsePrebuilt()
- }
- }
-
- // Otherwise, a module should only be used if it has not been replaced by a prebuilt.
- return !module.IsReplacedByPrebuilt()
+ return android.IsModulePreferred(module)
}
func (p *platformCompatConfigSingleton) GenerateBuildActions(ctx android.SingletonContext) {
diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go
index 8a442b5..c33e6c2 100644
--- a/java/prebuilt_apis.go
+++ b/java/prebuilt_apis.go
@@ -253,14 +253,8 @@
files := getPrebuiltFilesInSubdir(mctx, nextApiDir, "api/*incompatibilities.txt")
for _, f := range files {
localPath := strings.TrimPrefix(f, mydir)
- module, _, scope := parseApiFilePath(mctx, localPath)
-
- // Figure out which module is referenced by this file. Special case for "android".
- referencedModule := strings.TrimSuffix(module, "incompatibilities")
- referencedModule = strings.TrimSuffix(referencedModule, "-")
- if referencedModule == "" {
- referencedModule = "android"
- }
+ filename, _, scope := parseApiFilePath(mctx, localPath)
+ referencedModule := strings.TrimSuffix(filename, "-incompatibilities")
createApiModule(mctx, apiModuleName(referencedModule+"-incompatibilities", scope, "latest"), localPath)
diff --git a/java/rro.go b/java/rro.go
index 4ae0014..2e58c04 100644
--- a/java/rro.go
+++ b/java/rro.go
@@ -141,23 +141,23 @@
ctx.InstallFile(r.installDir, r.outputFile.Base(), r.outputFile)
}
-func (r *RuntimeResourceOverlay) SdkVersion() android.SdkSpec {
- return android.SdkSpecFrom(String(r.properties.Sdk_version))
+func (r *RuntimeResourceOverlay) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+ return android.SdkSpecFrom(ctx, String(r.properties.Sdk_version))
}
func (r *RuntimeResourceOverlay) SystemModules() string {
return ""
}
-func (r *RuntimeResourceOverlay) MinSdkVersion() android.SdkSpec {
+func (r *RuntimeResourceOverlay) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
if r.properties.Min_sdk_version != nil {
- return android.SdkSpecFrom(*r.properties.Min_sdk_version)
+ return android.SdkSpecFrom(ctx, *r.properties.Min_sdk_version)
}
- return r.SdkVersion()
+ return r.SdkVersion(ctx)
}
-func (r *RuntimeResourceOverlay) TargetSdkVersion() android.SdkSpec {
- return r.SdkVersion()
+func (r *RuntimeResourceOverlay) TargetSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+ return r.SdkVersion(ctx)
}
func (r *RuntimeResourceOverlay) Certificate() Certificate {
diff --git a/java/sdk.go b/java/sdk.go
index b546ca0..d6e20a7 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -51,9 +51,9 @@
if err != nil {
ctx.PropertyErrorf("sdk_version", "%s", err)
}
- if sdk <= 23 {
+ if sdk.FinalOrFutureInt() <= 23 {
return JAVA_VERSION_7
- } else if sdk <= 29 {
+ } else if sdk.FinalOrFutureInt() <= 29 {
return JAVA_VERSION_8
} else {
return JAVA_VERSION_9
@@ -61,7 +61,7 @@
}
func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext android.SdkContext) sdkDep {
- sdkVersion := sdkContext.SdkVersion()
+ sdkVersion := sdkContext.SdkVersion(ctx)
if !sdkVersion.Valid() {
ctx.PropertyErrorf("sdk_version", "invalid version %q", sdkVersion.Raw)
return sdkDep{}
@@ -76,11 +76,11 @@
}
if sdkVersion.UsePrebuilt(ctx) {
- dir := filepath.Join("prebuilts", "sdk", sdkVersion.Version.String(), sdkVersion.Kind.String())
+ dir := filepath.Join("prebuilts", "sdk", sdkVersion.ApiLevel.String(), sdkVersion.Kind.String())
jar := filepath.Join(dir, "android.jar")
// There's no aidl for other SDKs yet.
// TODO(77525052): Add aidl files for other SDKs too.
- publicDir := filepath.Join("prebuilts", "sdk", sdkVersion.Version.String(), "public")
+ publicDir := filepath.Join("prebuilts", "sdk", sdkVersion.ApiLevel.String(), "public")
aidl := filepath.Join(publicDir, "framework.aidl")
jarPath := android.ExistentPathForSource(ctx, jar)
aidlPath := android.ExistentPathForSource(ctx, aidl)
@@ -89,7 +89,7 @@
if (!jarPath.Valid() || !aidlPath.Valid()) && ctx.Config().AllowMissingDependencies() {
return sdkDep{
invalidVersion: true,
- bootclasspath: []string{fmt.Sprintf("sdk_%s_%s_android", sdkVersion.Kind, sdkVersion.Version.String())},
+ bootclasspath: []string{fmt.Sprintf("sdk_%s_%s_android", sdkVersion.Kind, sdkVersion.ApiLevel.String())},
}
}
@@ -105,7 +105,7 @@
var systemModules string
if defaultJavaLanguageVersion(ctx, sdkVersion).usesJavaModules() {
- systemModules = "sdk_public_" + sdkVersion.Version.String() + "_system_modules"
+ systemModules = "sdk_public_" + sdkVersion.ApiLevel.String() + "_system_modules"
}
return sdkDep{
diff --git a/java/sdk_library.go b/java/sdk_library.go
index ebb2154..e5ee397 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -201,8 +201,12 @@
return scope
}
+func (scope *apiScope) stubsLibraryModuleNameSuffix() string {
+ return ".stubs" + scope.moduleSuffix
+}
+
func (scope *apiScope) stubsLibraryModuleName(baseName string) string {
- return baseName + ".stubs" + scope.moduleSuffix
+ return baseName + scope.stubsLibraryModuleNameSuffix()
}
func (scope *apiScope) stubsSourceModuleName(baseName string) string {
@@ -817,7 +821,7 @@
func (c *commonToSdkLibraryAndImport) selectHeaderJarsForSdkVersion(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths {
// If a specific numeric version has been requested then use prebuilt versions of the sdk.
- if sdkVersion.Version.IsNumbered() {
+ if !sdkVersion.ApiLevel.IsPreview() {
return PrebuiltJars(ctx, c.moduleBase.BaseModuleName(), sdkVersion)
}
@@ -1466,15 +1470,15 @@
}
func PrebuiltJars(ctx android.BaseModuleContext, baseName string, s android.SdkSpec) android.Paths {
- var ver android.SdkVersion
+ var ver android.ApiLevel
var kind android.SdkKind
if s.UsePrebuilt(ctx) {
- ver = s.Version
+ ver = s.ApiLevel
kind = s.Kind
} else {
// We don't have prebuilt SDK for the specific sdkVersion.
// Instead of breaking the build, fallback to use "system_current"
- ver = android.SdkVersionCurrent
+ ver = android.FutureApiLevel
kind = android.SdkSystem
}
@@ -1508,7 +1512,7 @@
// force override sdk_version to module_current so that the closest possible API
// surface could be found in selectHeaderJarsForSdkVersion
if module.defaultsToStubs() && !sdkVersion.Specified() {
- sdkVersion = android.SdkSpecFrom("module_current")
+ sdkVersion = android.SdkSpecFrom(ctx, "module_current")
}
// Only provide access to the implementation library if it is actually built.
@@ -1684,16 +1688,20 @@
func moduleStubLinkType(name string) (stub bool, ret sdkLinkType) {
// This suffix-based approach is fragile and could potentially mis-trigger.
// TODO(b/155164730): Clean this up when modules no longer reference sdk_lib stubs directly.
- if strings.HasSuffix(name, ".stubs.public") || strings.HasSuffix(name, "-stubs-publicapi") {
+ if strings.HasSuffix(name, apiScopePublic.stubsLibraryModuleNameSuffix()) {
+ if name == "hwbinder.stubs" || name == "libcore_private.stubs" {
+ // Due to a previous bug, these modules were not considered stubs, so we retain that.
+ return false, javaPlatform
+ }
return true, javaSdk
}
- if strings.HasSuffix(name, ".stubs.system") || strings.HasSuffix(name, "-stubs-systemapi") {
+ if strings.HasSuffix(name, apiScopeSystem.stubsLibraryModuleNameSuffix()) {
return true, javaSystem
}
- if strings.HasSuffix(name, ".stubs.module_lib") || strings.HasSuffix(name, "-stubs-module_libs_api") {
+ if strings.HasSuffix(name, apiScopeModuleLib.stubsLibraryModuleNameSuffix()) {
return true, javaModule
}
- if strings.HasSuffix(name, ".stubs.test") {
+ if strings.HasSuffix(name, apiScopeTest.stubsLibraryModuleNameSuffix()) {
return true, javaSystem
}
return false, javaPlatform
@@ -1945,11 +1953,11 @@
}
// Add dependencies to the prebuilt stubs library
- ctx.AddVariationDependencies(nil, apiScope.stubsTag, "prebuilt_"+module.stubsLibraryModuleName(apiScope))
+ ctx.AddVariationDependencies(nil, apiScope.stubsTag, android.PrebuiltNameFromSource(module.stubsLibraryModuleName(apiScope)))
if len(scopeProperties.Stub_srcs) > 0 {
// Add dependencies to the prebuilt stubs source library
- ctx.AddVariationDependencies(nil, apiScope.stubsSourceTag, "prebuilt_"+module.stubsSourceModuleName(apiScope))
+ ctx.AddVariationDependencies(nil, apiScope.stubsSourceTag, android.PrebuiltNameFromSource(module.stubsSourceModuleName(apiScope)))
}
}
}
diff --git a/java/system_modules.go b/java/system_modules.go
index 8c69051..320a2bb 100644
--- a/java/system_modules.go
+++ b/java/system_modules.go
@@ -236,7 +236,7 @@
// modules.
func (system *systemModulesImport) ComponentDepsMutator(ctx android.BottomUpMutatorContext) {
for _, lib := range system.properties.Libs {
- ctx.AddVariationDependencies(nil, systemModulesLibsTag, "prebuilt_"+lib)
+ ctx.AddVariationDependencies(nil, systemModulesLibsTag, android.PrebuiltNameFromSource(lib))
}
}
diff --git a/java/testing.go b/java/testing.go
index 80c107d..aee0710 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -178,6 +178,43 @@
return fs
}
+// FixtureConfigureBootJars configures the boot jars in both the dexpreopt.GlobalConfig and
+// Config.productVariables structs. As a side effect that enables dexpreopt.
+func FixtureConfigureBootJars(bootJars ...string) android.FixturePreparer {
+ artBootJars := []string{}
+ for _, j := range bootJars {
+ artApex := false
+ for _, artApexName := range artApexNames {
+ if strings.HasPrefix(j, artApexName+":") {
+ artApex = true
+ break
+ }
+ }
+ if artApex {
+ artBootJars = append(artBootJars, j)
+ }
+ }
+ return android.GroupFixturePreparers(
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.BootJars = android.CreateTestConfiguredJarList(bootJars)
+ }),
+ dexpreopt.FixtureSetBootJars(bootJars...),
+ dexpreopt.FixtureSetArtBootJars(artBootJars...),
+ )
+}
+
+// FixtureConfigureUpdatableBootJars configures the updatable boot jars in both the
+// dexpreopt.GlobalConfig and Config.productVariables structs. As a side effect that enables
+// dexpreopt.
+func FixtureConfigureUpdatableBootJars(bootJars ...string) android.FixturePreparer {
+ return android.GroupFixturePreparers(
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.UpdatableBootJars = android.CreateTestConfiguredJarList(bootJars)
+ }),
+ dexpreopt.FixtureSetUpdatableBootJars(bootJars...),
+ )
+}
+
// registerRequiredBuildComponentsForTest registers the build components used by
// PrepareForTestWithJavaDefaultModules.
//
@@ -300,6 +337,46 @@
}
}
+// CheckPlatformBootclasspathModules returns the apex:module pair for the modules depended upon by
+// the platform-bootclasspath module.
+func CheckPlatformBootclasspathModules(t *testing.T, result *android.TestResult, name string, expected []string) {
+ t.Helper()
+ platformBootclasspath := result.Module(name, "android_common").(*platformBootclasspathModule)
+ pairs := ApexNamePairsFromModules(result.TestContext, platformBootclasspath.configuredModules)
+ android.AssertDeepEquals(t, fmt.Sprintf("%s modules", "platform-bootclasspath"), expected, pairs)
+}
+
+// ApexNamePairsFromModules returns the apex:module pair for the supplied modules.
+func ApexNamePairsFromModules(ctx *android.TestContext, modules []android.Module) []string {
+ pairs := []string{}
+ for _, module := range modules {
+ pairs = append(pairs, apexNamePairFromModule(ctx, module))
+ }
+ return pairs
+}
+
+func apexNamePairFromModule(ctx *android.TestContext, module android.Module) string {
+ name := module.Name()
+ var apex string
+ apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
+ if apexInfo.IsForPlatform() {
+ apex = "platform"
+ } else {
+ apex = apexInfo.InApexes[0]
+ }
+
+ return fmt.Sprintf("%s:%s", apex, name)
+}
+
+// CheckPlatformBootclasspathFragments returns the apex:module pair for the fragments depended upon
+// by the platform-bootclasspath module.
+func CheckPlatformBootclasspathFragments(t *testing.T, result *android.TestResult, name string, expected []string) {
+ t.Helper()
+ platformBootclasspath := result.Module(name, "android_common").(*platformBootclasspathModule)
+ pairs := ApexNamePairsFromModules(result.TestContext, platformBootclasspath.fragments)
+ android.AssertDeepEquals(t, fmt.Sprintf("%s fragments", "platform-bootclasspath"), expected, pairs)
+}
+
func CheckHiddenAPIRuleInputs(t *testing.T, expected string, hiddenAPIRule android.TestingBuildParams) {
t.Helper()
actual := strings.TrimSpace(strings.Join(android.NormalizePathsForTesting(hiddenAPIRule.Implicits), "\n"))
diff --git a/linkerconfig/linkerconfig.go b/linkerconfig/linkerconfig.go
index da80a47..241cac6 100644
--- a/linkerconfig/linkerconfig.go
+++ b/linkerconfig/linkerconfig.go
@@ -17,6 +17,7 @@
import (
"android/soong/android"
"android/soong/etc"
+ "fmt"
"github.com/google/blueprint/proptools"
)
@@ -68,6 +69,17 @@
return l.outputFilePath
}
+var _ android.OutputFileProducer = (*linkerConfig)(nil)
+
+func (l *linkerConfig) OutputFiles(tag string) (android.Paths, error) {
+ switch tag {
+ case "":
+ return android.Paths{l.outputFilePath}, nil
+ default:
+ return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+ }
+}
+
func (l *linkerConfig) GenerateAndroidBuildActions(ctx android.ModuleContext) {
inputFile := android.PathForModuleSrc(ctx, android.String(l.properties.Src))
l.outputFilePath = android.PathForModuleOut(ctx, "linker.config.pb").OutputPath
@@ -81,9 +93,10 @@
linkerConfigRule.Build("conv_linker_config",
"Generate linker config protobuf "+l.outputFilePath.String())
- if proptools.BoolDefault(l.properties.Installable, true) {
- ctx.InstallFile(l.installDirPath, l.outputFilePath.Base(), l.outputFilePath)
+ if !proptools.BoolDefault(l.properties.Installable, true) {
+ l.SkipInstall()
}
+ ctx.InstallFile(l.installDirPath, l.outputFilePath.Base(), l.outputFilePath)
}
// linker_config generates protobuf file from json file. This protobuf file will be used from
diff --git a/rust/Android.bp b/rust/Android.bp
index a29c474..a6c4e07 100644
--- a/rust/Android.bp
+++ b/rust/Android.bp
@@ -14,6 +14,7 @@
],
srcs: [
"androidmk.go",
+ "benchmark.go",
"binary.go",
"bindgen.go",
"builder.go",
@@ -35,6 +36,7 @@
"testing.go",
],
testSrcs: [
+ "benchmark_test.go",
"binary_test.go",
"bindgen_test.go",
"builder_test.go",
diff --git a/rust/androidmk.go b/rust/androidmk.go
index 0f9a17d..5f89d73 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -50,7 +50,7 @@
}
ret := android.AndroidMkEntries{
- OutputFile: mod.outputFile,
+ OutputFile: mod.unstrippedOutputFile,
Include: "$(BUILD_SYSTEM)/soong_rust_prebuilt.mk",
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
@@ -60,6 +60,10 @@
entries.AddStrings("LOCAL_SHARED_LIBRARIES", mod.Properties.AndroidMkSharedLibs...)
entries.AddStrings("LOCAL_STATIC_LIBRARIES", mod.Properties.AndroidMkStaticLibs...)
entries.AddStrings("LOCAL_SOONG_LINK_TYPE", mod.makeLinkType)
+ if mod.UseVndk() {
+ entries.SetBool("LOCAL_USE_VNDK", true)
+ }
+
},
},
}
@@ -70,6 +74,12 @@
// If the compiler is disabled, this is a SourceProvider.
mod.SubAndroidMk(&ret, mod.sourceProvider)
}
+
+ if mod.sanitize != nil {
+ mod.SubAndroidMk(&ret, mod.sanitize)
+ }
+
+ ret.SubName += mod.Properties.RustSubName
ret.SubName += mod.Properties.SubName
return []android.AndroidMkEntries{ret}
@@ -102,6 +112,20 @@
cc.AndroidMkWriteTestData(test.data, ret)
}
+func (benchmark *benchmarkDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) {
+ benchmark.binaryDecorator.AndroidMk(ctx, ret)
+ ret.Class = "NATIVE_TESTS"
+ ret.ExtraEntries = append(ret.ExtraEntries,
+ func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+ entries.AddCompatibilityTestSuites(benchmark.Properties.Test_suites...)
+ if benchmark.testConfig != nil {
+ entries.SetString("LOCAL_FULL_TEST_CONFIG", benchmark.testConfig.String())
+ }
+ entries.SetBool("LOCAL_NATIVE_BENCHMARK", true)
+ entries.SetBoolIfTrue("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", !BoolDefault(benchmark.Properties.Auto_gen_config, true))
+ })
+}
+
func (library *libraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) {
ctx.SubAndroidMk(ret, library.baseCompiler)
diff --git a/rust/benchmark.go b/rust/benchmark.go
new file mode 100644
index 0000000..b89f5cd
--- /dev/null
+++ b/rust/benchmark.go
@@ -0,0 +1,129 @@
+// Copyright 2020 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"
+ "android/soong/tradefed"
+)
+
+type BenchmarkProperties struct {
+ // Disables the creation of a test-specific directory when used with
+ // relative_install_path. Useful if several tests need to be in the same
+ // directory, but test_per_src doesn't work.
+ No_named_install_directory *bool
+
+ // the name of the test configuration (for example "AndroidBenchmark.xml") that should be
+ // installed with the module.
+ Test_config *string `android:"path,arch_variant"`
+
+ // the name of the test configuration template (for example "AndroidBenchmarkTemplate.xml") that
+ // should be installed with the module.
+ Test_config_template *string `android:"path,arch_variant"`
+
+ // list of compatibility suites (for example "cts", "vts") that the module should be
+ // installed into.
+ Test_suites []string `android:"arch_variant"`
+
+ // Flag to indicate whether or not to create test config automatically. If AndroidTest.xml
+ // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
+ // explicitly.
+ Auto_gen_config *bool
+}
+
+type benchmarkDecorator struct {
+ *binaryDecorator
+ Properties BenchmarkProperties
+ testConfig android.Path
+}
+
+func NewRustBenchmark(hod android.HostOrDeviceSupported) (*Module, *benchmarkDecorator) {
+ // Build both 32 and 64 targets for device benchmarks.
+ // Cannot build both for host benchmarks yet if the benchmark depends on
+ // something like proc-macro2 that cannot be built for both.
+ multilib := android.MultilibBoth
+ if hod != android.DeviceSupported && hod != android.HostAndDeviceSupported {
+ multilib = android.MultilibFirst
+ }
+ module := newModule(hod, multilib)
+
+ benchmark := &benchmarkDecorator{
+ binaryDecorator: &binaryDecorator{
+ baseCompiler: NewBaseCompiler("nativebench", "nativebench64", InstallInData),
+ },
+ }
+
+ module.compiler = benchmark
+ module.AddProperties(&benchmark.Properties)
+ return module, benchmark
+}
+
+func init() {
+ android.RegisterModuleType("rust_benchmark", RustBenchmarkFactory)
+ android.RegisterModuleType("rust_benchmark_host", RustBenchmarkHostFactory)
+}
+
+func RustBenchmarkFactory() android.Module {
+ module, _ := NewRustBenchmark(android.HostAndDeviceSupported)
+ return module.Init()
+}
+
+func RustBenchmarkHostFactory() android.Module {
+ module, _ := NewRustBenchmark(android.HostSupported)
+ return module.Init()
+}
+
+func (benchmark *benchmarkDecorator) autoDep(ctx android.BottomUpMutatorContext) autoDep {
+ return rlibAutoDep
+}
+
+func (benchmark *benchmarkDecorator) stdLinkage(ctx *depsContext) RustLinkage {
+ return RlibLinkage
+}
+
+func (benchmark *benchmarkDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
+ flags = benchmark.binaryDecorator.compilerFlags(ctx, flags)
+ return flags
+}
+
+func (benchmark *benchmarkDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps {
+ deps = benchmark.binaryDecorator.compilerDeps(ctx, deps)
+
+ deps.Rustlibs = append(deps.Rustlibs, "libcriterion")
+
+ return deps
+}
+
+func (benchmark *benchmarkDecorator) compilerProps() []interface{} {
+ return append(benchmark.binaryDecorator.compilerProps(), &benchmark.Properties)
+}
+
+func (benchmark *benchmarkDecorator) install(ctx ModuleContext) {
+ benchmark.testConfig = tradefed.AutoGenRustBenchmarkConfig(ctx,
+ benchmark.Properties.Test_config,
+ benchmark.Properties.Test_config_template,
+ benchmark.Properties.Test_suites,
+ nil,
+ benchmark.Properties.Auto_gen_config)
+
+ // default relative install path is module name
+ if !Bool(benchmark.Properties.No_named_install_directory) {
+ benchmark.baseCompiler.relative = ctx.ModuleName()
+ } else if String(benchmark.baseCompiler.Properties.Relative_install_path) == "" {
+ ctx.PropertyErrorf("no_named_install_directory", "Module install directory may only be disabled if relative_install_path is set")
+ }
+
+ benchmark.binaryDecorator.install(ctx)
+}
diff --git a/rust/benchmark_test.go b/rust/benchmark_test.go
new file mode 100644
index 0000000..734dda7
--- /dev/null
+++ b/rust/benchmark_test.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 (
+ "strings"
+ "testing"
+
+ "android/soong/android"
+)
+
+func TestRustBenchmark(t *testing.T) {
+ ctx := testRust(t, `
+ rust_benchmark_host {
+ name: "my_bench",
+ srcs: ["foo.rs"],
+ }`)
+
+ testingModule := ctx.ModuleForTests("my_bench", "linux_glibc_x86_64")
+ expectedOut := "my_bench/linux_glibc_x86_64/my_bench"
+ outPath := testingModule.Output("my_bench").Output.String()
+ if !strings.Contains(outPath, expectedOut) {
+ t.Errorf("wrong output path: %v; expected: %v", outPath, expectedOut)
+ }
+}
+
+func TestRustBenchmarkLinkage(t *testing.T) {
+ ctx := testRust(t, `
+ rust_benchmark {
+ name: "my_bench",
+ srcs: ["foo.rs"],
+ }`)
+
+ testingModule := ctx.ModuleForTests("my_bench", "android_arm64_armv8-a").Module().(*Module)
+
+ if !android.InList("libcriterion.rlib-std", testingModule.Properties.AndroidMkRlibs) {
+ t.Errorf("rlib-std variant for libcriterion not detected as a rustlib-defined rlib dependency for device rust_benchmark module")
+ }
+ if !android.InList("libstd", testingModule.Properties.AndroidMkRlibs) {
+ t.Errorf("Device rust_benchmark module 'my_bench' does not link libstd as an rlib")
+ }
+}
diff --git a/rust/builder.go b/rust/builder.go
index 9d462d4..208b734 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -21,7 +21,6 @@
"github.com/google/blueprint"
"android/soong/android"
- "android/soong/bloaty"
"android/soong/rust/config"
)
@@ -51,9 +50,12 @@
Command: "$envVars $clippyCmd " +
// Because clippy-driver uses rustc as backend, we need to have some output even during the linting.
// Use the metadata output as it has the smallest footprint.
- "--emit metadata -o $out $in ${libFlags} " +
- "$rustcFlags $clippyFlags",
+ "--emit metadata -o $out --emit dep-info=$out.d.raw $in ${libFlags} " +
+ "$rustcFlags $clippyFlags" +
+ " && grep \"^$out:\" $out.d.raw > $out.d",
CommandDeps: []string{"$clippyCmd"},
+ Deps: blueprint.DepsGCC,
+ Depfile: "$out.d",
},
"rustcFlags", "libFlags", "clippyFlags", "envVars")
@@ -251,8 +253,6 @@
implicits = append(implicits, clippyFile)
}
- bloaty.MeasureSizeForPath(ctx, outputFile)
-
ctx.Build(pctx, android.BuildParams{
Rule: rustc,
Description: "rustc " + main.Rel(),
diff --git a/rust/compiler.go b/rust/compiler.go
index 41b7371..bc034d7 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -76,7 +76,7 @@
// errors). The default value is "default".
Lints *string
- // flags to pass to rustc
+ // flags to pass to rustc. To enable configuration options or features, use the "cfgs" or "features" properties.
Flags []string `android:"path,arch_variant"`
// flags to pass to the linker
@@ -125,6 +125,9 @@
// list of features to enable for this crate
Features []string `android:"arch_variant"`
+ // list of configuration options to enable for this crate. To enable features, use the "features" property.
+ Cfgs []string `android:"arch_variant"`
+
// specific rust edition that should be used if the default version is not desired
Edition *string `android:"arch_variant"`
@@ -210,9 +213,17 @@
return []interface{}{&compiler.Properties}
}
-func (compiler *baseCompiler) featuresToFlags(features []string) []string {
+func (compiler *baseCompiler) cfgsToFlags() []string {
flags := []string{}
- for _, feature := range features {
+ for _, cfg := range compiler.Properties.Cfgs {
+ flags = append(flags, "--cfg '"+cfg+"'")
+ }
+ return flags
+}
+
+func (compiler *baseCompiler) featuresToFlags() []string {
+ flags := []string{}
+ for _, feature := range compiler.Properties.Features {
flags = append(flags, "--cfg 'feature=\""+feature+"\"'")
}
return flags
@@ -226,7 +237,8 @@
}
flags.RustFlags = append(flags.RustFlags, lintFlags)
flags.RustFlags = append(flags.RustFlags, compiler.Properties.Flags...)
- flags.RustFlags = append(flags.RustFlags, compiler.featuresToFlags(compiler.Properties.Features)...)
+ flags.RustFlags = append(flags.RustFlags, compiler.cfgsToFlags()...)
+ flags.RustFlags = append(flags.RustFlags, compiler.featuresToFlags()...)
flags.RustFlags = append(flags.RustFlags, "--edition="+compiler.edition())
flags.LinkFlags = append(flags.LinkFlags, compiler.Properties.Ld_flags...)
flags.GlobalRustFlags = append(flags.GlobalRustFlags, config.GlobalRustFlags...)
@@ -272,6 +284,10 @@
return false
}
+func (compiler *baseCompiler) strippedOutputFilePath() android.OptionalPath {
+ return compiler.strippedOutputFile
+}
+
func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps {
deps.Rlibs = append(deps.Rlibs, compiler.Properties.Rlibs...)
deps.Dylibs = append(deps.Dylibs, compiler.Properties.Dylibs...)
@@ -287,7 +303,6 @@
if ctx.Target().Os == android.BuildOs {
stdlib = stdlib + "_" + ctx.toolchain().RustTriple()
}
-
deps.Stdlibs = append(deps.Stdlibs, stdlib)
}
}
@@ -328,6 +343,10 @@
if !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) {
dir = filepath.Join(dir, ctx.Arch().ArchType.String())
}
+
+ if compiler.location == InstallInData && ctx.RustModule().UseVndk() {
+ dir = filepath.Join(dir, "vendor")
+ }
return android.PathForModuleInstall(ctx, dir, compiler.subDir,
compiler.relativeInstallPath(), compiler.relative)
}
@@ -337,10 +356,7 @@
}
func (compiler *baseCompiler) install(ctx ModuleContext) {
- path := ctx.RustModule().outputFile
- if compiler.strippedOutputFile.Valid() {
- path = compiler.strippedOutputFile
- }
+ path := ctx.RustModule().OutputFile()
compiler.path = ctx.InstallFile(compiler.installDir(ctx), path.Path().Base(), path.Path())
}
diff --git a/rust/compiler_test.go b/rust/compiler_test.go
index c752762..5ca9e7f 100644
--- a/rust/compiler_test.go
+++ b/rust/compiler_test.go
@@ -42,6 +42,27 @@
}
}
+// Test that cfgs flags are being correctly generated.
+func TestCfgsToFlags(t *testing.T) {
+ ctx := testRust(t, `
+ rust_library_host {
+ name: "libfoo",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ cfgs: [
+ "std",
+ "cfg1=\"one\""
+ ],
+ }`)
+
+ libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
+
+ if !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'std'") ||
+ !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'cfg1=\"one\"'") {
+ t.Fatalf("missing std and cfg1 flags for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
+ }
+}
+
// Test that we reject multiple source files.
func TestEnforceSingleSourceFile(t *testing.T) {
diff --git a/rust/config/allowed_list.go b/rust/config/allowed_list.go
index 408d433..394fcc5 100644
--- a/rust/config/allowed_list.go
+++ b/rust/config/allowed_list.go
@@ -19,9 +19,11 @@
"packages/modules/Virtualization",
"prebuilts/rust",
"system/bt",
+ "system/core/libstats/pull_rust",
"system/extras/profcollectd",
"system/extras/simpleperf",
"system/hardware/interfaces/keystore2",
+ "system/logging/rust",
"system/security",
"system/tools/aidl",
}
diff --git a/rust/config/global.go b/rust/config/global.go
index 9208ddb..18776ab 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -24,7 +24,7 @@
var pctx = android.NewPackageContext("android/soong/rust/config")
var (
- RustDefaultVersion = "1.50.0"
+ RustDefaultVersion = "1.51.0"
RustDefaultBase = "prebuilts/rust/"
DefaultEdition = "2018"
Stdlibs = []string{
diff --git a/rust/config/lints.go b/rust/config/lints.go
index 7c05e4f..ef6b315 100644
--- a/rust/config/lints.go
+++ b/rust/config/lints.go
@@ -54,6 +54,7 @@
"-A clippy::type-complexity",
"-A clippy::unnecessary-wraps",
"-A clippy::unusual-byte-groupings",
+ "-A clippy::upper-case-acronyms",
}
// Rust lints for vendor code.
diff --git a/rust/fuzz.go b/rust/fuzz.go
index 6035e68..d699971 100644
--- a/rust/fuzz.go
+++ b/rust/fuzz.go
@@ -70,10 +70,9 @@
}
func (fuzzer *fuzzDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps {
- deps.StaticLibs = append(deps.StaticLibs,
- config.LibFuzzerRuntimeLibrary(ctx.toolchain()))
- deps.SharedLibs = append(deps.SharedLibs,
- config.LibclangRuntimeLibrary(ctx.toolchain(), "asan"))
+ if libFuzzerRuntimeLibrary := config.LibFuzzerRuntimeLibrary(ctx.toolchain()); libFuzzerRuntimeLibrary != "" {
+ deps.StaticLibs = append(deps.StaticLibs, libFuzzerRuntimeLibrary)
+ }
deps.SharedLibs = append(deps.SharedLibs, "libc++")
deps.Rlibs = append(deps.Rlibs, "liblibfuzzer_sys")
diff --git a/rust/fuzz_test.go b/rust/fuzz_test.go
index f93ccc7..2524f91 100644
--- a/rust/fuzz_test.go
+++ b/rust/fuzz_test.go
@@ -37,9 +37,6 @@
// Check that appropriate dependencies are added and that the rustlib linkage is correct.
fuzz_libtest_mod := ctx.ModuleForTests("fuzz_libtest", "android_arm64_armv8-a_fuzzer").Module().(*Module)
- if !android.InList("libclang_rt.asan-aarch64-android", fuzz_libtest_mod.Properties.AndroidMkSharedLibs) {
- t.Errorf("libclang_rt.asan-aarch64-android shared library dependency missing for rust_fuzz module.")
- }
if !android.InList("liblibfuzzer_sys.rlib-std", fuzz_libtest_mod.Properties.AndroidMkRlibs) {
t.Errorf("liblibfuzzer_sys rlib library dependency missing for rust_fuzz module. %#v", fuzz_libtest_mod.Properties.AndroidMkRlibs)
}
@@ -49,18 +46,18 @@
// Check that compiler flags are set appropriately .
fuzz_libtest := ctx.ModuleForTests("fuzz_libtest", "android_arm64_armv8-a_fuzzer").Output("fuzz_libtest")
- if !strings.Contains(fuzz_libtest.Args["rustcFlags"], "-Z sanitizer=address") ||
+ if !strings.Contains(fuzz_libtest.Args["rustcFlags"], "-Z sanitizer=hwaddress") ||
!strings.Contains(fuzz_libtest.Args["rustcFlags"], "-C passes='sancov'") ||
!strings.Contains(fuzz_libtest.Args["rustcFlags"], "--cfg fuzzing") {
- t.Errorf("rust_fuzz module does not contain the expected flags (sancov, cfg fuzzing, address sanitizer).")
+ t.Errorf("rust_fuzz module does not contain the expected flags (sancov, cfg fuzzing, hwaddress sanitizer).")
}
// Check that dependencies have 'fuzzer' variants produced for them as well.
libtest_fuzzer := ctx.ModuleForTests("libtest_fuzzing", "android_arm64_armv8-a_rlib_rlib-std_fuzzer").Output("libtest_fuzzing.rlib")
- if !strings.Contains(libtest_fuzzer.Args["rustcFlags"], "-Z sanitizer=address") ||
+ if !strings.Contains(libtest_fuzzer.Args["rustcFlags"], "-Z sanitizer=hwaddress") ||
!strings.Contains(libtest_fuzzer.Args["rustcFlags"], "-C passes='sancov'") ||
!strings.Contains(libtest_fuzzer.Args["rustcFlags"], "--cfg fuzzing") {
- t.Errorf("rust_fuzz dependent library does not contain the expected flags (sancov, cfg fuzzing, address sanitizer).")
+ t.Errorf("rust_fuzz dependent library does not contain the expected flags (sancov, cfg fuzzing, hwaddress sanitizer).")
}
}
diff --git a/rust/image.go b/rust/image.go
index 628aca3..900842e 100644
--- a/rust/image.go
+++ b/rust/image.go
@@ -23,6 +23,68 @@
var _ android.ImageInterface = (*Module)(nil)
+var _ cc.ImageMutatableModule = (*Module)(nil)
+
+func (mod *Module) VendorAvailable() bool {
+ return Bool(mod.VendorProperties.Vendor_available)
+}
+
+func (mod *Module) OdmAvailable() bool {
+ return Bool(mod.VendorProperties.Odm_available)
+}
+
+func (mod *Module) ProductAvailable() bool {
+ return false
+}
+
+func (mod *Module) RamdiskAvailable() bool {
+ return false
+}
+
+func (mod *Module) VendorRamdiskAvailable() bool {
+ return Bool(mod.Properties.Vendor_ramdisk_available)
+}
+
+func (mod *Module) AndroidModuleBase() *android.ModuleBase {
+ return &mod.ModuleBase
+}
+
+func (mod *Module) RecoveryAvailable() bool {
+ return false
+}
+
+func (mod *Module) ExtraVariants() []string {
+ return mod.Properties.ExtraVariants
+}
+
+func (mod *Module) AppendExtraVariant(extraVariant string) {
+ mod.Properties.ExtraVariants = append(mod.Properties.ExtraVariants, extraVariant)
+}
+
+func (mod *Module) SetRamdiskVariantNeeded(b bool) {
+ if b {
+ panic("Setting ramdisk variant needed for Rust module is unsupported: " + mod.BaseModuleName())
+ }
+}
+
+func (mod *Module) SetVendorRamdiskVariantNeeded(b bool) {
+ mod.Properties.VendorRamdiskVariantNeeded = b
+}
+
+func (mod *Module) SetRecoveryVariantNeeded(b bool) {
+ if b {
+ panic("Setting recovery variant needed for Rust module is unsupported: " + mod.BaseModuleName())
+ }
+}
+
+func (mod *Module) SetCoreVariantNeeded(b bool) {
+ mod.Properties.CoreVariantNeeded = b
+}
+
+func (mod *Module) SnapshotVersion(mctx android.BaseModuleContext) string {
+ panic("Rust modules do not support snapshotting: " + mod.BaseModuleName())
+}
+
func (mod *Module) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
return mod.Properties.VendorRamdiskVariantNeeded
}
@@ -35,6 +97,10 @@
return mod.InRamdisk()
}
+func (mod *Module) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+ return false
+}
+
func (mod *Module) RecoveryVariantNeeded(android.BaseModuleContext) bool {
return mod.InRecovery()
}
@@ -43,6 +109,29 @@
return mod.Properties.ExtraVariants
}
+func (mod *Module) IsSnapshotPrebuilt() bool {
+ // Rust does not support prebuilts in its snapshots
+ return false
+}
+
+func (ctx *moduleContext) SocSpecific() bool {
+ // Additionally check if this module is inVendor() that means it is a "vendor" variant of a
+ // module. As well as SoC specific modules, vendor variants must be installed to /vendor
+ // unless they have "odm_available: true".
+ return ctx.ModuleContext.SocSpecific() || (ctx.RustModule().InVendor() && !ctx.RustModule().VendorVariantToOdm())
+}
+
+func (ctx *moduleContext) DeviceSpecific() bool {
+ // Some vendor variants want to be installed to /odm by setting "odm_available: true".
+ return ctx.ModuleContext.DeviceSpecific() || (ctx.RustModule().InVendor() && ctx.RustModule().VendorVariantToOdm())
+}
+
+// Returns true when this module creates a vendor variant and wants to install the vendor variant
+// to the odm partition.
+func (c *Module) VendorVariantToOdm() bool {
+ return Bool(c.VendorProperties.Odm_available)
+}
+
func (ctx *moduleContext) ProductSpecific() bool {
return false
}
@@ -84,10 +173,15 @@
return mod.HasVendorVariant() || mod.HasProductVariant()
}
-func (c *Module) InProduct() bool {
+func (mod *Module) InProduct() bool {
return false
}
+// Returns true if the module is "vendor" variant. Usually these modules are installed in /vendor
+func (mod *Module) InVendor() bool {
+ return mod.Properties.ImageVariationPrefix == cc.VendorVariationPrefix
+}
+
func (mod *Module) SetImageVariation(ctx android.BaseModuleContext, variant string, module android.Module) {
m := module.(*Module)
if variant == android.VendorRamdiskVariation {
@@ -107,9 +201,6 @@
}
func (mod *Module) ImageMutatorBegin(mctx android.BaseModuleContext) {
- vendorSpecific := mctx.SocSpecific() || mctx.DeviceSpecific()
- platformVndkVersion := mctx.DeviceConfig().PlatformVndkVersion()
-
// Rust does not support installing to the product image yet.
if Bool(mod.VendorProperties.Product_available) {
mctx.PropertyErrorf("product_available",
@@ -121,60 +212,19 @@
mctx.PropertyErrorf("double_loadable",
"Rust modules do not yet support double loading")
}
-
- coreVariantNeeded := true
- vendorRamdiskVariantNeeded := false
-
- var vendorVariants []string
-
- if mod.HasVendorVariant() {
- prop := "vendor_available"
- if Bool(mod.VendorProperties.Odm_available) {
- prop = "odm_available"
- }
-
- if vendorSpecific {
- mctx.PropertyErrorf(prop,
- "doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific: true`")
- }
-
- if lib, ok := mod.compiler.(libraryInterface); ok {
- // Explicitly disallow rust_ffi variants which produce shared libraries from setting vendor_available.
- // Vendor variants do not produce an error for dylibs, rlibs with dylib-std linkage are disabled in the respective library
- // mutators until support is added.
- //
- // We can't check shared() here because image mutator is called before the library mutator, so we need to
- // check buildShared()
- if lib.buildShared() {
- mctx.PropertyErrorf(prop, "cannot be set for rust_ffi or rust_ffi_shared modules.")
- } else {
- vendorVariants = append(vendorVariants, platformVndkVersion)
- }
- }
- }
-
if Bool(mod.Properties.Vendor_ramdisk_available) {
if lib, ok := mod.compiler.(libraryInterface); !ok || (ok && lib.buildShared()) {
mctx.PropertyErrorf("vendor_ramdisk_available", "cannot be set for rust_ffi or rust_ffi_shared modules.")
- } else {
- vendorRamdiskVariantNeeded = true
}
}
- if vendorSpecific {
- if lib, ok := mod.compiler.(libraryInterface); !ok || (ok && (lib.buildShared() || lib.buildDylib() || lib.buildRlib())) {
- mctx.ModuleErrorf("Rust vendor specific modules are currently only supported for rust_ffi_static modules.")
- } else {
- coreVariantNeeded = false
- vendorVariants = append(vendorVariants, platformVndkVersion)
+ cc.MutateImage(mctx, mod)
+
+ if !mod.Properties.CoreVariantNeeded || mod.HasNonSystemVariants() {
+
+ if _, ok := mod.compiler.(*prebuiltLibraryDecorator); ok {
+ // Rust does not support prebuilt libraries on non-System images.
+ mctx.ModuleErrorf("Rust prebuilt modules not supported for non-system images.")
}
}
-
- mod.Properties.CoreVariantNeeded = coreVariantNeeded
- mod.Properties.VendorRamdiskVariantNeeded = vendorRamdiskVariantNeeded
-
- for _, variant := range android.FirstUniqueStrings(vendorVariants) {
- mod.Properties.ExtraVariants = append(mod.Properties.ExtraVariants, cc.VendorVariationPrefix+variant)
- }
-
}
diff --git a/rust/image_test.go b/rust/image_test.go
index e40599c..95e788f 100644
--- a/rust/image_test.go
+++ b/rust/image_test.go
@@ -38,10 +38,10 @@
}
`)
- vendorBinary := ctx.ModuleForTests("fizz_vendor", "android_vendor.VER_arm64_armv8-a").Module().(*cc.Module)
+ vendorBinary := ctx.ModuleForTests("fizz_vendor", "android_vendor.29_arm64_armv8-a").Module().(*cc.Module)
- if !android.InList("libfoo_vendor", vendorBinary.Properties.AndroidMkStaticLibs) {
- t.Errorf("vendorBinary should have a dependency on libfoo_vendor")
+ if !android.InList("libfoo_vendor.vendor", vendorBinary.Properties.AndroidMkStaticLibs) {
+ t.Errorf("vendorBinary should have a dependency on libfoo_vendor: %#v", vendorBinary.Properties.AndroidMkStaticLibs)
}
}
@@ -56,7 +56,7 @@
}
`)
- vendor := ctx.ModuleForTests("libfoo", "android_vendor.VER_arm64_armv8-a_static").Rule("rustc")
+ vendor := ctx.ModuleForTests("libfoo", "android_vendor.29_arm64_armv8-a_static").Rule("rustc")
if !strings.Contains(vendor.Args["rustcFlags"], "--cfg 'android_vndk'") {
t.Errorf("missing \"--cfg 'android_vndk'\" for libfoo vendor variant, rustcFlags: %#v", vendor.Args["rustcFlags"])
@@ -87,47 +87,19 @@
}
}
-// Test that shared libraries cannot be made vendor available until proper support is added.
+// Test that prebuilt libraries cannot be made vendor available.
func TestForbiddenVendorLinkage(t *testing.T) {
- testRustError(t, "cannot be set for rust_ffi or rust_ffi_shared modules.", `
- rust_ffi_shared {
- name: "libfoo_vendor",
- crate_name: "foo",
- srcs: ["foo.rs"],
- vendor_available: true,
- }
- `)
- testRustError(t, "cannot be set for rust_ffi or rust_ffi_shared modules.", `
- rust_ffi_shared {
- name: "libfoo_vendor",
- crate_name: "foo",
- srcs: ["foo.rs"],
- vendor_ramdisk_available: true,
- }
- `)
- testRustError(t, "Rust vendor specific modules are currently only supported for rust_ffi_static modules.", `
- rust_ffi {
- name: "libfoo_vendor",
- crate_name: "foo",
- srcs: ["foo.rs"],
+ testRustVndkError(t, "Rust prebuilt modules not supported for non-system images.", `
+ rust_prebuilt_library {
+ name: "librust_prebuilt",
+ crate_name: "rust_prebuilt",
+ rlib: {
+ srcs: ["libtest.rlib"],
+ },
+ dylib: {
+ srcs: ["libtest.so"],
+ },
vendor: true,
}
- `)
- testRustError(t, "Rust vendor specific modules are currently only supported for rust_ffi_static modules.", `
- rust_library {
- name: "libfoo_vendor",
- crate_name: "foo",
- srcs: ["foo.rs"],
- vendor: true,
- }
- `)
- testRustError(t, "Rust vendor specific modules are currently only supported for rust_ffi_static modules.", `
- rust_binary {
- name: "foo_vendor",
- crate_name: "foo",
- srcs: ["foo.rs"],
- vendor: true,
- }
- `)
-
+ `)
}
diff --git a/rust/library.go b/rust/library.go
index 71fe1f5..26c104c 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -475,7 +475,7 @@
TransformSrctoShared(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
}
- if !library.rlib() && library.stripper.NeedsStrip(ctx) {
+ if !library.rlib() && !library.static() && library.stripper.NeedsStrip(ctx) {
strippedOutputFile := android.PathForModuleOut(ctx, "stripped", fileName)
library.stripper.StripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile)
library.strippedOutputFile = android.OptionalPathForPath(strippedOutputFile)
@@ -596,9 +596,9 @@
v.(*Module).compiler.(libraryInterface).setRlib()
case dylibVariation:
v.(*Module).compiler.(libraryInterface).setDylib()
- if v.(*Module).ModuleBase.ImageVariation().Variation != android.CoreVariation {
+ if v.(*Module).ModuleBase.ImageVariation().Variation == android.VendorRamdiskVariation {
// TODO(b/165791368)
- // Disable dylib non-core variations until we support these.
+ // Disable dylib Vendor Ramdisk variations until we support these.
v.(*Module).Disable()
}
case "source":
@@ -637,14 +637,14 @@
dylib := modules[1].(*Module)
rlib.compiler.(libraryInterface).setRlibStd()
dylib.compiler.(libraryInterface).setDylibStd()
- if dylib.ModuleBase.ImageVariation().Variation != android.CoreVariation {
+ if dylib.ModuleBase.ImageVariation().Variation == android.VendorRamdiskVariation {
// TODO(b/165791368)
- // Disable rlibs that link against dylib-std on non-core variations until non-core dylib
+ // Disable rlibs that link against dylib-std on vendor ramdisk variations until those dylib
// variants are properly supported.
dylib.Disable()
}
- rlib.Properties.SubName += RlibStdlibSuffix
- dylib.Properties.SubName += DylibStdlibSuffix
+ rlib.Properties.RustSubName += RlibStdlibSuffix
+ dylib.Properties.RustSubName += DylibStdlibSuffix
}
}
}
diff --git a/rust/rust.go b/rust/rust.go
index f0d0e36..9738b46 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -22,6 +22,7 @@
"github.com/google/blueprint/proptools"
"android/soong/android"
+ "android/soong/bloaty"
"android/soong/cc"
cc_config "android/soong/cc/config"
"android/soong/rust/config"
@@ -73,6 +74,11 @@
VndkVersion string `blueprint:"mutated"`
SubName string `blueprint:"mutated"`
+ // SubName is used by CC for tracking image variants / SDK versions. RustSubName is used for Rust-specific
+ // subnaming which shouldn't be visible to CC modules (such as the rlib stdlinkage subname). This should be
+ // appended before SubName.
+ RustSubName string `blueprint:"mutated"`
+
// Set by imageMutator
CoreVariantNeeded bool `blueprint:"mutated"`
VendorRamdiskVariantNeeded bool `blueprint:"mutated"`
@@ -114,7 +120,10 @@
sourceProvider SourceProvider
subAndroidMkOnce map[SubAndroidMkProvider]bool
- outputFile android.OptionalPath
+ // Unstripped output. This is usually used when this module is linked to another module
+ // as a library. The stripped output which is used for installation can be found via
+ // compiler.strippedOutputFile if it exists.
+ unstrippedOutputFile android.OptionalPath
hideApexVariantFromMake bool
}
@@ -128,11 +137,6 @@
mod.Properties.PreventInstall = true
}
-// Returns true if the module is "vendor" variant. Usually these modules are installed in /vendor
-func (mod *Module) InVendor() bool {
- return mod.Properties.ImageVariationPrefix == cc.VendorVariationPrefix
-}
-
func (mod *Module) SetHideFromMake() {
mod.Properties.HideFromMake = true
}
@@ -163,8 +167,8 @@
if mod.sourceProvider != nil && (mod.compiler == nil || mod.compiler.Disabled()) {
return mod.sourceProvider.Srcs(), nil
} else {
- if mod.outputFile.Valid() {
- return android.Paths{mod.outputFile.Path()}, nil
+ if mod.OutputFile().Valid() {
+ return android.Paths{mod.OutputFile().Path()}, nil
}
return android.Paths{}, nil
}
@@ -228,7 +232,11 @@
}
func (mod *Module) MustUseVendorVariant() bool {
- return false
+ return true
+}
+
+func (mod *Module) SubName() string {
+ return mod.Properties.SubName
}
func (mod *Module) IsVndk() bool {
@@ -252,6 +260,22 @@
return false
}
+func (m *Module) IsLlndkHeaders() bool {
+ return false
+}
+
+func (m *Module) IsLlndkLibrary() bool {
+ return false
+}
+
+func (mod *Module) KernelHeadersDecorator() bool {
+ return false
+}
+
+func (m *Module) HasLlndkStubs() bool {
+ return false
+}
+
func (mod *Module) SdkVersion() string {
return ""
}
@@ -346,6 +370,8 @@
stdLinkage(ctx *depsContext) RustLinkage
isDependencyRoot() bool
+
+ strippedOutputFilePath() android.OptionalPath
}
type exportedFlagsProducer interface {
@@ -429,6 +455,7 @@
module.AddProperties(
&BaseProperties{},
&cc.VendorProperties{},
+ &BenchmarkProperties{},
&BindgenProperties{},
&BaseCompilerProperties{},
&BinaryCompilerProperties{},
@@ -523,7 +550,10 @@
}
func (mod *Module) OutputFile() android.OptionalPath {
- return mod.outputFile
+ if mod.compiler != nil && mod.compiler.strippedOutputFilePath().Valid() {
+ return mod.compiler.strippedOutputFilePath()
+ }
+ return mod.unstrippedOutputFile
}
func (mod *Module) CoverageFiles() android.Paths {
@@ -540,7 +570,7 @@
return false
}
- return mod.outputFile.Valid() && !mod.Properties.PreventInstall
+ return mod.OutputFile().Valid() && !mod.Properties.PreventInstall
}
var _ cc.LinkableInterface = (*Module)(nil)
@@ -721,9 +751,9 @@
if mod.compiler != nil && !mod.compiler.Disabled() {
mod.compiler.initialize(ctx)
- outputFile := mod.compiler.compile(ctx, flags, deps)
-
- mod.outputFile = android.OptionalPathForPath(outputFile)
+ unstrippedOutputFile := mod.compiler.compile(ctx, flags, deps)
+ mod.unstrippedOutputFile = android.OptionalPathForPath(unstrippedOutputFile)
+ bloaty.MeasureSizeForPaths(ctx, mod.compiler.strippedOutputFilePath(), mod.unstrippedOutputFile)
apexInfo := actx.Provider(android.ApexInfoProvider).(android.ApexInfo)
if mod.installable(apexInfo) {
@@ -790,6 +820,11 @@
return ok && tag == dylibDepTag
}
+func IsRlibDepTag(depTag blueprint.DependencyTag) bool {
+ tag, ok := depTag.(dependencyTag)
+ return ok && tag == rlibDepTag
+}
+
type autoDep struct {
variation string
depTag dependencyTag
@@ -829,8 +864,10 @@
ctx.VisitDirectDeps(func(dep android.Module) {
depName := ctx.OtherModuleName(dep)
depTag := ctx.OtherModuleDependencyTag(dep)
+
if rustDep, ok := dep.(*Module); ok && !rustDep.CcLibraryInterface() {
//Handle Rust Modules
+ makeLibName := cc.MakeLibName(ctx, mod, rustDep, depName+rustDep.Properties.RustSubName)
switch depTag {
case dylibDepTag:
@@ -840,19 +877,19 @@
return
}
directDylibDeps = append(directDylibDeps, rustDep)
- mod.Properties.AndroidMkDylibs = append(mod.Properties.AndroidMkDylibs, depName)
+ mod.Properties.AndroidMkDylibs = append(mod.Properties.AndroidMkDylibs, makeLibName)
case rlibDepTag:
rlib, ok := rustDep.compiler.(libraryInterface)
if !ok || !rlib.rlib() {
- ctx.ModuleErrorf("mod %q not an rlib library", depName+rustDep.Properties.SubName)
+ ctx.ModuleErrorf("mod %q not an rlib library", makeLibName)
return
}
directRlibDeps = append(directRlibDeps, rustDep)
- mod.Properties.AndroidMkRlibs = append(mod.Properties.AndroidMkRlibs, depName+rustDep.Properties.SubName)
+ mod.Properties.AndroidMkRlibs = append(mod.Properties.AndroidMkRlibs, makeLibName)
case procMacroDepTag:
directProcMacroDeps = append(directProcMacroDeps, rustDep)
- mod.Properties.AndroidMkProcMacroLibs = append(mod.Properties.AndroidMkProcMacroLibs, depName)
+ mod.Properties.AndroidMkProcMacroLibs = append(mod.Properties.AndroidMkProcMacroLibs, makeLibName)
case android.SourceDepTag:
// Since these deps are added in path_properties.go via AddDependencies, we need to ensure the correct
// OS/Arch variant is used.
@@ -882,7 +919,7 @@
}
if depTag == dylibDepTag || depTag == rlibDepTag || depTag == procMacroDepTag {
- linkFile := rustDep.outputFile
+ linkFile := rustDep.unstrippedOutputFile
if !linkFile.Valid() {
ctx.ModuleErrorf("Invalid output file when adding dep %q to %q",
depName, ctx.ModuleName())
@@ -896,6 +933,7 @@
} else if ccDep, ok := dep.(cc.LinkableInterface); ok {
//Handle C dependencies
+ makeLibName := cc.MakeLibName(ctx, mod, ccDep, depName)
if _, ok := ccDep.(*Module); !ok {
if ccDep.Module().Target().Os != ctx.Os() {
ctx.ModuleErrorf("OS mismatch between %q and %q", ctx.ModuleName(), depName)
@@ -937,7 +975,7 @@
depPaths.depClangFlags = append(depPaths.depClangFlags, exportedInfo.Flags...)
depPaths.depGeneratedHeaders = append(depPaths.depGeneratedHeaders, exportedInfo.GeneratedHeaders...)
directStaticLibDeps = append(directStaticLibDeps, ccDep)
- mod.Properties.AndroidMkStaticLibs = append(mod.Properties.AndroidMkStaticLibs, depName)
+ mod.Properties.AndroidMkStaticLibs = append(mod.Properties.AndroidMkStaticLibs, makeLibName)
case cc.IsSharedDepTag(depTag):
depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
depPaths.linkObjects = append(depPaths.linkObjects, linkObject.String())
@@ -947,7 +985,7 @@
depPaths.depClangFlags = append(depPaths.depClangFlags, exportedInfo.Flags...)
depPaths.depGeneratedHeaders = append(depPaths.depGeneratedHeaders, exportedInfo.GeneratedHeaders...)
directSharedLibDeps = append(directSharedLibDeps, ccDep)
- mod.Properties.AndroidMkSharedLibs = append(mod.Properties.AndroidMkSharedLibs, depName)
+ mod.Properties.AndroidMkSharedLibs = append(mod.Properties.AndroidMkSharedLibs, makeLibName)
exportDep = true
case cc.IsHeaderDepTag(depTag):
exportedInfo := ctx.OtherModuleProvider(dep, cc.FlagExporterInfoProvider).(cc.FlagExporterInfo)
@@ -978,15 +1016,15 @@
var rlibDepFiles RustLibraries
for _, dep := range directRlibDeps {
- rlibDepFiles = append(rlibDepFiles, RustLibrary{Path: dep.outputFile.Path(), CrateName: dep.CrateName()})
+ rlibDepFiles = append(rlibDepFiles, RustLibrary{Path: dep.unstrippedOutputFile.Path(), CrateName: dep.CrateName()})
}
var dylibDepFiles RustLibraries
for _, dep := range directDylibDeps {
- dylibDepFiles = append(dylibDepFiles, RustLibrary{Path: dep.outputFile.Path(), CrateName: dep.CrateName()})
+ dylibDepFiles = append(dylibDepFiles, RustLibrary{Path: dep.unstrippedOutputFile.Path(), CrateName: dep.CrateName()})
}
var procMacroDepFiles RustLibraries
for _, dep := range directProcMacroDeps {
- procMacroDepFiles = append(procMacroDepFiles, RustLibrary{Path: dep.outputFile.Path(), CrateName: dep.CrateName()})
+ procMacroDepFiles = append(procMacroDepFiles, RustLibrary{Path: dep.unstrippedOutputFile.Path(), CrateName: dep.CrateName()})
}
var staticLibDepFiles android.Paths
diff --git a/rust/rust_test.go b/rust/rust_test.go
index 418bd93..6ae05d9 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -75,7 +75,7 @@
func(variables android.FixtureProductVariables) {
variables.DeviceVndkVersion = StringPtr("current")
variables.ProductVndkVersion = StringPtr("current")
- variables.Platform_vndk_version = StringPtr("VER")
+ variables.Platform_vndk_version = StringPtr("29")
},
),
).RunTestWithBp(t, bp)
@@ -113,6 +113,24 @@
RunTestWithBp(t, bp)
}
+// testRustVndkError is similar to testRustError, but can be used to test VNDK-related errors.
+func testRustVndkError(t *testing.T, pattern string, bp string) {
+ skipTestIfOsNotSupported(t)
+ android.GroupFixturePreparers(
+ prepareForRustTest,
+ rustMockedFiles.AddToFixture(),
+ android.FixtureModifyProductVariables(
+ func(variables android.FixtureProductVariables) {
+ variables.DeviceVndkVersion = StringPtr("current")
+ variables.ProductVndkVersion = StringPtr("current")
+ variables.Platform_vndk_version = StringPtr("VER")
+ },
+ ),
+ ).
+ ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(pattern)).
+ RunTestWithBp(t, bp)
+}
+
// testRustCtx is used to build a particular test environment. Unless your
// tests requires a specific setup, prefer the wrapping functions: testRust,
// testRustCov or testRustError.
@@ -384,3 +402,17 @@
_ = ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_dylib-std")
_ = ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_rlib_dylib-std")
}
+
+// Test that library size measurements are generated.
+func TestLibrarySizes(t *testing.T) {
+ ctx := testRust(t, `
+ rust_library_dylib {
+ name: "libwaldo",
+ srcs: ["foo.rs"],
+ crate_name: "waldo",
+ }`)
+
+ m := ctx.SingletonForTests("file_metrics")
+ m.Output("libwaldo.dylib.so.bloaty.csv")
+ m.Output("stripped/libwaldo.dylib.so.bloaty.csv")
+}
diff --git a/rust/sanitize.go b/rust/sanitize.go
index 2f44b20..0a53f98 100644
--- a/rust/sanitize.go
+++ b/rust/sanitize.go
@@ -23,11 +23,12 @@
)
type SanitizeProperties struct {
- // enable AddressSanitizer, ThreadSanitizer, or UndefinedBehaviorSanitizer
+ // enable AddressSanitizer, HWAddressSanitizer, and others.
Sanitize struct {
- Address *bool `android:"arch_variant"`
- Fuzzer *bool `android:"arch_variant"`
- Never *bool `android:"arch_variant"`
+ Address *bool `android:"arch_variant"`
+ Hwaddress *bool `android:"arch_variant"`
+ Fuzzer *bool `android:"arch_variant"`
+ Never *bool `android:"arch_variant"`
}
SanitizerEnabled bool `blueprint:"mutated"`
SanitizeDep bool `blueprint:"mutated"`
@@ -40,13 +41,11 @@
"-C passes='sancov'",
"--cfg fuzzing",
- "-C llvm-args=-sanitizer-coverage-level=4",
+ "-C llvm-args=-sanitizer-coverage-level=3",
"-C llvm-args=-sanitizer-coverage-trace-compares",
"-C llvm-args=-sanitizer-coverage-inline-8bit-counters",
"-C llvm-args=-sanitizer-coverage-trace-geps",
"-C llvm-args=-sanitizer-coverage-prune-blocks=0",
- "-C llvm-args=-sanitizer-coverage-pc-table",
- "-Z sanitizer=address",
// Sancov breaks with lto
// TODO: Remove when https://bugs.llvm.org/show_bug.cgi?id=41734 is resolved and sancov works with LTO
@@ -57,6 +56,11 @@
"-Z sanitizer=address",
}
+var hwasanFlags = []string{
+ "-Z sanitizer=hwaddress",
+ "-C target-feature=+tagged-globals",
+}
+
func boolPtr(v bool) *bool {
if v {
return &v
@@ -83,6 +87,15 @@
if ctx.Os() == android.Android && Bool(s.Address) {
sanitize.Properties.SanitizerEnabled = true
}
+
+ // HWASan requires AArch64 hardware feature (top-byte-ignore).
+ if ctx.Arch().ArchType != android.Arm64 {
+ s.Hwaddress = nil
+ }
+
+ if ctx.Os() == android.Android && Bool(s.Hwaddress) {
+ sanitize.Properties.SanitizerEnabled = true
+ }
}
type sanitize struct {
@@ -95,10 +108,18 @@
}
if Bool(sanitize.Properties.Sanitize.Fuzzer) {
flags.RustFlags = append(flags.RustFlags, fuzzerFlags...)
+ if ctx.Arch().ArchType == android.Arm64 {
+ flags.RustFlags = append(flags.RustFlags, hwasanFlags...)
+ } else {
+ flags.RustFlags = append(flags.RustFlags, asanFlags...)
+ }
}
if Bool(sanitize.Properties.Sanitize.Address) {
flags.RustFlags = append(flags.RustFlags, asanFlags...)
}
+ if Bool(sanitize.Properties.Sanitize.Hwaddress) {
+ flags.RustFlags = append(flags.RustFlags, hwasanFlags...)
+ }
return flags, deps
}
@@ -111,11 +132,40 @@
if !mod.Enabled() {
return
}
- if Bool(mod.sanitize.Properties.Sanitize.Fuzzer) || Bool(mod.sanitize.Properties.Sanitize.Address) {
- mctx.AddFarVariationDependencies(append(mctx.Target().Variations(), []blueprint.Variation{
- {Mutator: "link", Variation: "shared"},
- }...), cc.SharedDepTag(), config.LibclangRuntimeLibrary(mod.toolchain(mctx), "asan"))
+
+ variations := mctx.Target().Variations()
+ var depTag blueprint.DependencyTag
+ var deps []string
+
+ if mod.IsSanitizerEnabled(cc.Asan) ||
+ (mod.IsSanitizerEnabled(cc.Fuzzer) && mctx.Arch().ArchType != android.Arm64) {
+ variations = append(variations,
+ blueprint.Variation{Mutator: "link", Variation: "shared"})
+ depTag = cc.SharedDepTag()
+ deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "asan")}
+ } else if mod.IsSanitizerEnabled(cc.Hwasan) ||
+ (mod.IsSanitizerEnabled(cc.Fuzzer) && mctx.Arch().ArchType == android.Arm64) {
+ // TODO(b/180495975): HWASan for static Rust binaries isn't supported yet.
+ if binary, ok := mod.compiler.(*binaryDecorator); ok {
+ if Bool(binary.Properties.Static_executable) {
+ mctx.ModuleErrorf("HWASan is not supported for static Rust executables yet.")
+ }
+ }
+
+ if mod.StaticallyLinked() {
+ variations = append(variations,
+ blueprint.Variation{Mutator: "link", Variation: "static"})
+ depTag = cc.StaticDepTag(false)
+ deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "hwasan_static")}
+ } else {
+ variations = append(variations,
+ blueprint.Variation{Mutator: "link", Variation: "shared"})
+ depTag = cc.SharedDepTag()
+ deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "hwasan")}
+ }
}
+
+ mctx.AddFarVariationDependencies(variations, depTag, deps...)
}
}
@@ -128,6 +178,9 @@
case cc.Asan:
sanitize.Properties.Sanitize.Address = boolPtr(b)
sanitizerSet = true
+ case cc.Hwasan:
+ sanitize.Properties.Sanitize.Hwaddress = boolPtr(b)
+ sanitizerSet = true
default:
panic(fmt.Errorf("setting unsupported sanitizerType %d", t))
}
@@ -169,11 +222,23 @@
return sanitize.Properties.Sanitize.Fuzzer
case cc.Asan:
return sanitize.Properties.Sanitize.Address
+ case cc.Hwasan:
+ return sanitize.Properties.Sanitize.Hwaddress
default:
return nil
}
}
+func (sanitize *sanitize) AndroidMk(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+ // Add a suffix for hwasan rlib libraries to allow surfacing both the sanitized and
+ // non-sanitized variants to make without a name conflict.
+ if entries.Class == "RLIB_LIBRARIES" || entries.Class == "STATIC_LIBRARIES" {
+ if sanitize.isSanitizerEnabled(cc.Hwasan) {
+ entries.SubName += ".hwasan"
+ }
+ }
+}
+
func (mod *Module) SanitizerSupported(t cc.SanitizerType) bool {
if mod.Host() {
return false
@@ -183,6 +248,8 @@
return true
case cc.Asan:
return true
+ case cc.Hwasan:
+ return true
default:
return false
}
@@ -224,11 +291,9 @@
func (mod *Module) StaticallyLinked() bool {
if lib, ok := mod.compiler.(libraryInterface); ok {
- if lib.rlib() || lib.static() {
- return true
- }
- } else if Bool(mod.compiler.(*binaryDecorator).Properties.Static_executable) {
- return true
+ return lib.rlib() || lib.static()
+ } else if binary, ok := mod.compiler.(*binaryDecorator); ok {
+ return Bool(binary.Properties.Static_executable)
}
return false
}
diff --git a/rust/testing.go b/rust/testing.go
index 75adcfc..a0f86b2 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -16,6 +16,7 @@
import (
"android/soong/android"
+ "android/soong/bloaty"
"android/soong/cc"
)
@@ -34,6 +35,7 @@
// Preparer that will define default rust modules, e.g. standard prebuilt modules.
var PrepareForTestWithRustDefaultModules = android.GroupFixturePreparers(
cc.PrepareForTestWithCcDefaultModules,
+ bloaty.PrepareForTestWithBloatyDefaultModules,
PrepareForTestWithRustBuildComponents,
android.FixtureAddTextFile(rustDefaultsDir+"Android.bp", GatherRequiredDepsForTest()),
)
@@ -127,6 +129,7 @@
system_shared_libs: [],
apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
min_sdk_version: "29",
+ vendor_available: true,
}
cc_library {
name: "libprotobuf-cpp-full",
@@ -150,7 +153,7 @@
host_supported: true,
vendor_available: true,
vendor_ramdisk_available: true,
- native_coverage: false,
+ native_coverage: false,
sysroot: true,
apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
min_sdk_version: "29",
@@ -163,7 +166,7 @@
host_supported: true,
vendor_available: true,
vendor_ramdisk_available: true,
- native_coverage: false,
+ native_coverage: false,
sysroot: true,
apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
min_sdk_version: "29",
@@ -192,11 +195,19 @@
srcs:["foo.rs"],
host_supported: true,
}
+ rust_library {
+ name: "libcriterion",
+ crate_name: "criterion",
+ srcs:["foo.rs"],
+ host_supported: true,
+ }
`
return bp
}
func registerRequiredBuildComponentsForTest(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("rust_benchmark", RustBenchmarkFactory)
+ ctx.RegisterModuleType("rust_benchmark_host", RustBenchmarkHostFactory)
ctx.RegisterModuleType("rust_binary", RustBinaryFactory)
ctx.RegisterModuleType("rust_binary_host", RustBinaryHostFactory)
ctx.RegisterModuleType("rust_bindgen", RustBindgenFactory)
diff --git a/scripts/Android.bp b/scripts/Android.bp
index 9e8a602..c54b2bc 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -254,3 +254,22 @@
"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-ndk-prebuilts.sh b/scripts/build-ndk-prebuilts.sh
index c27f098..a1fa48d 100755
--- a/scripts/build-ndk-prebuilts.sh
+++ b/scripts/build-ndk-prebuilts.sh
@@ -54,7 +54,6 @@
"Safestack": false,
"Ndk_abis": true,
- "Exclude_draft_ndk_apis": true,
"VendorVars": {
"art_module": {
diff --git a/scripts/conv_classpaths_proto.py b/scripts/conv_classpaths_proto.py
new file mode 100644
index 0000000..f49fbbb
--- /dev/null
+++ b/scripts/conv_classpaths_proto.py
@@ -0,0 +1,76 @@
+# 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/conv_linker_config.py b/scripts/conv_linker_config.py
index 22fe9f6..92f79da 100644
--- a/scripts/conv_linker_config.py
+++ b/scripts/conv_linker_config.py
@@ -78,6 +78,14 @@
with open(args.output, 'wb') as f:
f.write(pb.SerializeToString())
+def Merge(args):
+ pb = linker_config_pb2.LinkerConfig()
+ for other in args.input:
+ with open(other, 'rb') as f:
+ pb.MergeFromString(f.read())
+
+ with open(args.out, 'wb') as f:
+ f.write(pb.SerializeToString())
def GetArgParser():
parser = argparse.ArgumentParser()
@@ -161,6 +169,22 @@
help='Values of the libraries to append. If there are more than one it should be separated by empty space')
append.set_defaults(func=Append)
+ append = subparsers.add_parser(
+ 'merge', help='Merge configurations')
+ append.add_argument(
+ '-o',
+ '--out',
+ required=True,
+ type=str,
+ help='Ouptut linker configuration file to write in protobuf.')
+ append.add_argument(
+ '-i',
+ '--input',
+ nargs='+',
+ type=str,
+ help='Linker configuration files to merge.')
+ append.set_defaults(func=Merge)
+
return parser
diff --git a/scripts/strip.sh b/scripts/strip.sh
index 43e6cbf..e3e5273 100755
--- a/scripts/strip.sh
+++ b/scripts/strip.sh
@@ -18,7 +18,6 @@
# Inputs:
# Environment:
# CLANG_BIN: path to the clang bin directory
-# CROSS_COMPILE: prefix added to readelf, objcopy tools
# XZ: path to the xz binary
# Arguments:
# -i ${file}: input file (required)
@@ -69,7 +68,7 @@
KEEP_SYMBOLS="--strip-unneeded-symbol=* --keep-symbols="
KEEP_SYMBOLS+="${outfile}.symbolList"
- "${CROSS_COMPILE}objcopy" -w "${infile}" "${outfile}.tmp" ${KEEP_SYMBOLS}
+ "${CLANG_BIN}/llvm-objcopy" -w "${infile}" "${outfile}.tmp" ${KEEP_SYMBOLS}
}
do_strip_keep_mini_debug_info() {
@@ -78,18 +77,13 @@
"${CLANG_BIN}/llvm-strip" --strip-all --keep-section=.ARM.attributes --remove-section=.comment "${infile}" -o "${outfile}.tmp" || fail=true
if [ -z $fail ]; then
- # Current prebult llvm-objcopy does not support --only-keep-debug flag,
- # and cannot process object files that are produced with the flag. Use
- # GNU objcopy instead for now. (b/141010852)
- "${CROSS_COMPILE}objcopy" --only-keep-debug "${infile}" "${outfile}.debug"
+ "${CLANG_BIN}/llvm-objcopy" --only-keep-debug "${infile}" "${outfile}.debug"
"${CLANG_BIN}/llvm-nm" -D "${infile}" --format=posix --defined-only 2> /dev/null | awk '{ print $1 }' | sort >"${outfile}.dynsyms"
"${CLANG_BIN}/llvm-nm" "${infile}" --format=posix --defined-only | awk '{ if ($2 == "T" || $2 == "t" || $2 == "D") print $1 }' | sort > "${outfile}.funcsyms"
comm -13 "${outfile}.dynsyms" "${outfile}.funcsyms" > "${outfile}.keep_symbols"
echo >> "${outfile}.keep_symbols" # Ensure that the keep_symbols file is not empty.
- "${CROSS_COMPILE}objcopy" --rename-section .debug_frame=saved_debug_frame "${outfile}.debug" "${outfile}.mini_debuginfo"
- "${CROSS_COMPILE}objcopy" -S --remove-section .gdb_index --remove-section .comment --remove-section .rustc --keep-symbols="${outfile}.keep_symbols" "${outfile}.mini_debuginfo"
- "${CROSS_COMPILE}objcopy" --rename-section saved_debug_frame=.debug_frame "${outfile}.mini_debuginfo"
- "${XZ}" --block-size=64k --threads=0 "${outfile}.mini_debuginfo"
+ "${CLANG_BIN}/llvm-objcopy" -S --keep-section .debug_frame --keep-symbols="${outfile}.keep_symbols" "${outfile}.debug" "${outfile}.mini_debuginfo"
+ "${XZ}" --keep --block-size=64k --threads=0 "${outfile}.mini_debuginfo"
"${CLANG_BIN}/llvm-objcopy" --add-section .gnu_debugdata="${outfile}.mini_debuginfo.xz" "${outfile}.tmp"
rm -f "${outfile}.dynsyms" "${outfile}.funcsyms" "${outfile}.keep_symbols" "${outfile}.debug" "${outfile}.mini_debuginfo" "${outfile}.mini_debuginfo.xz"
@@ -196,7 +190,6 @@
cat <<EOF > "${depsfile}"
${outfile}: \
${infile} \
- ${CROSS_COMPILE}objcopy \
${CLANG_BIN}/llvm-nm \
${CLANG_BIN}/llvm-objcopy \
${CLANG_BIN}/llvm-readelf \
diff --git a/sdk/update.go b/sdk/update.go
index 828c7b6..522a888 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -1350,7 +1350,7 @@
// Compute the list of possible os types that this sdk could support.
func (s *sdk) getPossibleOsTypes() []android.OsType {
var osTypes []android.OsType
- for _, osType := range android.OsTypeList {
+ for _, osType := range android.OsTypeList() {
if s.DeviceSupported() {
if osType.Class == android.Device && osType != android.Fuchsia {
osTypes = append(osTypes, osType)
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index 6623381..42d5680 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -210,6 +210,10 @@
return proptools.Bool(s.properties.Vendor_ramdisk_available) || s.ModuleBase.InstallInVendorRamdisk()
}
+func (s *ShBinary) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+ return false
+}
+
func (s *ShBinary) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
return proptools.Bool(s.properties.Recovery_available) || s.ModuleBase.InstallInRecovery()
}
diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go
index f42f9e9..6d35f9c 100644
--- a/sysprop/sysprop_test.go
+++ b/sysprop/sysprop_test.go
@@ -129,7 +129,7 @@
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
variables.DeviceSystemSdkVersions = []string{"28"}
variables.DeviceVndkVersion = proptools.StringPtr("current")
- variables.Platform_vndk_version = proptools.StringPtr("VER")
+ variables.Platform_vndk_version = proptools.StringPtr("29")
}),
mockFS.AddToFixture(),
android.FixtureWithRootAndroidBp(bp),
@@ -246,10 +246,10 @@
// Check for generated cc_library
for _, variant := range []string{
- "android_vendor.VER_arm_armv7-a-neon_shared",
- "android_vendor.VER_arm_armv7-a-neon_static",
- "android_vendor.VER_arm64_armv8-a_shared",
- "android_vendor.VER_arm64_armv8-a_static",
+ "android_vendor.29_arm_armv7-a-neon_shared",
+ "android_vendor.29_arm_armv7-a-neon_static",
+ "android_vendor.29_arm64_armv8-a_shared",
+ "android_vendor.29_arm64_armv8-a_static",
} {
result.ModuleForTests("libsysprop-platform", variant)
result.ModuleForTests("libsysprop-vendor", variant)
@@ -277,15 +277,15 @@
// Check for exported includes
coreVariant := "android_arm64_armv8-a_static"
- vendorVariant := "android_vendor.VER_arm64_armv8-a_static"
+ vendorVariant := "android_vendor.29_arm64_armv8-a_static"
platformInternalPath := "libsysprop-platform/android_arm64_armv8-a_static/gen/sysprop/include"
platformPublicCorePath := "libsysprop-platform/android_arm64_armv8-a_static/gen/sysprop/public/include"
- platformPublicVendorPath := "libsysprop-platform/android_vendor.VER_arm64_armv8-a_static/gen/sysprop/public/include"
+ platformPublicVendorPath := "libsysprop-platform/android_vendor.29_arm64_armv8-a_static/gen/sysprop/public/include"
platformOnProductPath := "libsysprop-platform-on-product/android_arm64_armv8-a_static/gen/sysprop/public/include"
- vendorInternalPath := "libsysprop-vendor/android_vendor.VER_arm64_armv8-a_static/gen/sysprop/include"
+ vendorInternalPath := "libsysprop-vendor/android_vendor.29_arm64_armv8-a_static/gen/sysprop/include"
vendorPublicPath := "libsysprop-vendor-on-product/android_arm64_armv8-a_static/gen/sysprop/public/include"
platformClient := result.ModuleForTests("cc-client-platform", coreVariant)
diff --git a/tests/bootstrap_test.sh b/tests/bootstrap_test.sh
new file mode 100755
index 0000000..a483370
--- /dev/null
+++ b/tests/bootstrap_test.sh
@@ -0,0 +1,580 @@
+#!/bin/bash -eu
+
+# This test exercises the bootstrapping process of the build system
+# in a source tree that only contains enough files for Bazel and Soong to work.
+
+source "$(dirname "$0")/lib.sh"
+
+function test_smoke {
+ setup
+ run_soong
+}
+
+function test_null_build() {
+ setup
+ run_soong
+ local bootstrap_mtime1=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
+ local output_mtime1=$(stat -c "%y" out/soong/build.ninja)
+ run_soong
+ local bootstrap_mtime2=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
+ local output_mtime2=$(stat -c "%y" out/soong/build.ninja)
+
+ if [[ "$bootstrap_mtime1" == "$bootstrap_mtime2" ]]; then
+ # Bootstrapping is always done. It doesn't take a measurable amount of time.
+ fail "Bootstrap Ninja file did not change on null build"
+ fi
+
+ if [[ "$output_mtime1" != "$output_mtime2" ]]; then
+ fail "Output Ninja file changed on null build"
+ fi
+}
+
+function test_soong_build_rebuilt_if_blueprint_changes() {
+ setup
+ run_soong
+ local mtime1=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
+
+ sed -i 's/pluginGenSrcCmd/pluginGenSrcCmd2/g' build/blueprint/bootstrap/bootstrap.go
+
+ run_soong
+ local mtime2=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
+
+ if [[ "$mtime1" == "$mtime2" ]]; then
+ fail "Bootstrap Ninja file did not change"
+ fi
+}
+
+function test_change_android_bp() {
+ setup
+ mkdir -p a
+ cat > a/Android.bp <<'EOF'
+python_binary_host {
+ name: "my_little_binary_host",
+ srcs: ["my_little_binary_host.py"]
+}
+EOF
+ touch a/my_little_binary_host.py
+ run_soong
+
+ grep -q "^# Module:.*my_little_binary_host" out/soong/build.ninja || fail "module not found"
+
+ cat > a/Android.bp <<'EOF'
+python_binary_host {
+ name: "my_great_binary_host",
+ srcs: ["my_great_binary_host.py"]
+}
+EOF
+ touch a/my_great_binary_host.py
+ run_soong
+
+ grep -q "^# Module:.*my_little_binary_host" out/soong/build.ninja && fail "old module found"
+ grep -q "^# Module:.*my_great_binary_host" out/soong/build.ninja || fail "new module not found"
+}
+
+
+function test_add_android_bp() {
+ setup
+ run_soong
+ local mtime1=$(stat -c "%y" out/soong/build.ninja)
+
+ mkdir -p a
+ cat > a/Android.bp <<'EOF'
+python_binary_host {
+ name: "my_little_binary_host",
+ srcs: ["my_little_binary_host.py"]
+}
+EOF
+ touch a/my_little_binary_host.py
+ run_soong
+
+ local mtime2=$(stat -c "%y" out/soong/build.ninja)
+ if [[ "$mtime1" == "$mtime2" ]]; then
+ fail "Output Ninja file did not change"
+ fi
+
+ grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja || fail "New module not in output"
+
+ run_soong
+}
+
+function test_delete_android_bp() {
+ setup
+ mkdir -p a
+ cat > a/Android.bp <<'EOF'
+python_binary_host {
+ name: "my_little_binary_host",
+ srcs: ["my_little_binary_host.py"]
+}
+EOF
+ touch a/my_little_binary_host.py
+ run_soong
+
+ grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja || fail "Module not in output"
+
+ rm a/Android.bp
+ run_soong
+
+ if grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja; then
+ fail "Old module in output"
+ fi
+}
+
+# Test that an incremental build with a glob doesn't rerun soong_build, and
+# only regenerates the globs on the first but not the second incremental build.
+function test_glob_noop_incremental() {
+ setup
+
+ mkdir -p a
+ cat > a/Android.bp <<'EOF'
+python_binary_host {
+ name: "my_little_binary_host",
+ srcs: ["*.py"],
+}
+EOF
+ touch a/my_little_binary_host.py
+ run_soong
+ local ninja_mtime1=$(stat -c "%y" out/soong/build.ninja)
+
+ local glob_deps_file=out/soong/.glob/a/__py.glob.d
+
+ if [ -e "$glob_deps_file" ]; then
+ fail "Glob deps file unexpectedly written on first build"
+ fi
+
+ run_soong
+ local ninja_mtime2=$(stat -c "%y" out/soong/build.ninja)
+
+ # There is an ineffiencency in glob that requires bpglob to rerun once for each glob to update
+ # the entry in the .ninja_log. It doesn't update the output file, but we can detect the rerun
+ # by checking if the deps file was created.
+ if [ ! -e "$glob_deps_file" ]; then
+ fail "Glob deps file missing after second build"
+ fi
+
+ local glob_deps_mtime2=$(stat -c "%y" "$glob_deps_file")
+
+ if [[ "$ninja_mtime1" != "$ninja_mtime2" ]]; then
+ fail "Ninja file rewritten on null incremental build"
+ fi
+
+ run_soong
+ local ninja_mtime3=$(stat -c "%y" out/soong/build.ninja)
+ local glob_deps_mtime3=$(stat -c "%y" "$glob_deps_file")
+
+ if [[ "$ninja_mtime2" != "$ninja_mtime3" ]]; then
+ fail "Ninja file rewritten on null incremental build"
+ fi
+
+ # The bpglob commands should not rerun after the first incremental build.
+ if [[ "$glob_deps_mtime2" != "$glob_deps_mtime3" ]]; then
+ fail "Glob deps file rewritten on second null incremental build"
+ fi
+}
+
+function test_add_file_to_glob() {
+ setup
+
+ mkdir -p a
+ cat > a/Android.bp <<'EOF'
+python_binary_host {
+ name: "my_little_binary_host",
+ srcs: ["*.py"],
+}
+EOF
+ touch a/my_little_binary_host.py
+ run_soong
+ local mtime1=$(stat -c "%y" out/soong/build.ninja)
+
+ touch a/my_little_library.py
+ run_soong
+
+ local mtime2=$(stat -c "%y" out/soong/build.ninja)
+ if [[ "$mtime1" == "$mtime2" ]]; then
+ fail "Output Ninja file did not change"
+ fi
+
+ grep -q my_little_library.py out/soong/build.ninja || fail "new file is not in output"
+}
+
+function test_soong_build_rerun_iff_environment_changes() {
+ setup
+
+ mkdir -p cherry
+ cat > cherry/Android.bp <<'EOF'
+bootstrap_go_package {
+ name: "cherry",
+ pkgPath: "android/soong/cherry",
+ deps: [
+ "blueprint",
+ "soong",
+ "soong-android",
+ ],
+ srcs: [
+ "cherry.go",
+ ],
+ pluginFor: ["soong_build"],
+}
+EOF
+
+ cat > cherry/cherry.go <<'EOF'
+package cherry
+
+import (
+ "android/soong/android"
+ "github.com/google/blueprint"
+)
+
+var (
+ pctx = android.NewPackageContext("cherry")
+)
+
+func init() {
+ android.RegisterSingletonType("cherry", CherrySingleton)
+}
+
+func CherrySingleton() android.Singleton {
+ return &cherrySingleton{}
+}
+
+type cherrySingleton struct{}
+
+func (p *cherrySingleton) GenerateBuildActions(ctx android.SingletonContext) {
+ cherryRule := ctx.Rule(pctx, "cherry",
+ blueprint.RuleParams{
+ Command: "echo CHERRY IS " + ctx.Config().Getenv("CHERRY") + " > ${out}",
+ CommandDeps: []string{},
+ Description: "Cherry",
+ })
+
+ outputFile := android.PathForOutput(ctx, "cherry", "cherry.txt")
+ var deps android.Paths
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: cherryRule,
+ Output: outputFile,
+ Inputs: deps,
+ })
+}
+EOF
+
+ export CHERRY=TASTY
+ run_soong
+ grep -q "CHERRY IS TASTY" out/soong/build.ninja \
+ || fail "first value of environment variable is not used"
+
+ export CHERRY=RED
+ run_soong
+ grep -q "CHERRY IS RED" out/soong/build.ninja \
+ || fail "second value of environment variable not used"
+ local mtime1=$(stat -c "%y" out/soong/build.ninja)
+
+ run_soong
+ local mtime2=$(stat -c "%y" out/soong/build.ninja)
+ if [[ "$mtime1" != "$mtime2" ]]; then
+ fail "Output Ninja file changed when environment variable did not"
+ fi
+
+}
+
+function test_add_file_to_soong_build() {
+ setup
+ run_soong
+ local mtime1=$(stat -c "%y" out/soong/build.ninja)
+
+ mkdir -p a
+ cat > a/Android.bp <<'EOF'
+bootstrap_go_package {
+ name: "picard-soong-rules",
+ pkgPath: "android/soong/picard",
+ deps: [
+ "blueprint",
+ "soong",
+ "soong-android",
+ ],
+ srcs: [
+ "picard.go",
+ ],
+ pluginFor: ["soong_build"],
+}
+EOF
+
+ cat > a/picard.go <<'EOF'
+package picard
+
+import (
+ "android/soong/android"
+ "github.com/google/blueprint"
+)
+
+var (
+ pctx = android.NewPackageContext("picard")
+)
+
+func init() {
+ android.RegisterSingletonType("picard", PicardSingleton)
+}
+
+func PicardSingleton() android.Singleton {
+ return &picardSingleton{}
+}
+
+type picardSingleton struct{}
+
+func (p *picardSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+ picardRule := ctx.Rule(pctx, "picard",
+ blueprint.RuleParams{
+ Command: "echo Make it so. > ${out}",
+ CommandDeps: []string{},
+ Description: "Something quotable",
+ })
+
+ outputFile := android.PathForOutput(ctx, "picard", "picard.txt")
+ var deps android.Paths
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: picardRule,
+ Output: outputFile,
+ Inputs: deps,
+ })
+}
+
+EOF
+
+ run_soong
+ local mtime2=$(stat -c "%y" out/soong/build.ninja)
+ if [[ "$mtime1" == "$mtime2" ]]; then
+ fail "Output Ninja file did not change"
+ fi
+
+ grep -q "Make it so" out/soong/build.ninja || fail "New action not present"
+}
+
+# Tests a glob in a build= statement in an Android.bp file, which is interpreted
+# during bootstrapping.
+function test_glob_during_bootstrapping() {
+ setup
+
+ mkdir -p a
+ cat > a/Android.bp <<'EOF'
+build=["foo*.bp"]
+EOF
+ cat > a/fooa.bp <<'EOF'
+bootstrap_go_package {
+ name: "picard-soong-rules",
+ pkgPath: "android/soong/picard",
+ deps: [
+ "blueprint",
+ "soong",
+ "soong-android",
+ ],
+ srcs: [
+ "picard.go",
+ ],
+ pluginFor: ["soong_build"],
+}
+EOF
+
+ cat > a/picard.go <<'EOF'
+package picard
+
+import (
+ "android/soong/android"
+ "github.com/google/blueprint"
+)
+
+var (
+ pctx = android.NewPackageContext("picard")
+)
+
+func init() {
+ android.RegisterSingletonType("picard", PicardSingleton)
+}
+
+func PicardSingleton() android.Singleton {
+ return &picardSingleton{}
+}
+
+type picardSingleton struct{}
+
+var Message = "Make it so."
+
+func (p *picardSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+ picardRule := ctx.Rule(pctx, "picard",
+ blueprint.RuleParams{
+ Command: "echo " + Message + " > ${out}",
+ CommandDeps: []string{},
+ Description: "Something quotable",
+ })
+
+ outputFile := android.PathForOutput(ctx, "picard", "picard.txt")
+ var deps android.Paths
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: picardRule,
+ Output: outputFile,
+ Inputs: deps,
+ })
+}
+
+EOF
+
+ run_soong
+ local mtime1=$(stat -c "%y" out/soong/build.ninja)
+
+ grep -q "Make it so" out/soong/build.ninja || fail "Original action not present"
+
+ cat > a/foob.bp <<'EOF'
+bootstrap_go_package {
+ name: "worf-soong-rules",
+ pkgPath: "android/soong/worf",
+ deps: [
+ "blueprint",
+ "soong",
+ "soong-android",
+ "picard-soong-rules",
+ ],
+ srcs: [
+ "worf.go",
+ ],
+ pluginFor: ["soong_build"],
+}
+EOF
+
+ cat > a/worf.go <<'EOF'
+package worf
+
+import "android/soong/picard"
+
+func init() {
+ picard.Message = "Engage."
+}
+EOF
+
+ run_soong
+ local mtime2=$(stat -c "%y" out/soong/build.ninja)
+ if [[ "$mtime1" == "$mtime2" ]]; then
+ fail "Output Ninja file did not change"
+ fi
+
+ grep -q "Engage" out/soong/build.ninja || fail "New action not present"
+
+ if grep -q "Make it so" out/soong/build.ninja; then
+ fail "Original action still present"
+ fi
+}
+
+function test_null_build_after_docs {
+ setup
+ run_soong
+ local mtime1=$(stat -c "%y" out/soong/build.ninja)
+
+ prebuilts/build-tools/linux-x86/bin/ninja -f out/soong/build.ninja soong_docs
+ run_soong
+ local mtime2=$(stat -c "%y" out/soong/build.ninja)
+
+ if [[ "$mtime1" != "$mtime2" ]]; then
+ fail "Output Ninja file changed on null build"
+ fi
+}
+
+function test_integrated_bp2build_smoke {
+ setup
+ INTEGRATED_BP2BUILD=1 run_soong
+ if [[ ! -e out/soong/.bootstrap/bp2build_workspace_marker ]]; then
+ fail "bp2build marker file not created"
+ fi
+}
+
+function test_integrated_bp2build_add_android_bp {
+ setup
+
+ mkdir -p a
+ touch a/a.txt
+ cat > a/Android.bp <<'EOF'
+filegroup {
+ name: "a",
+ srcs: ["a.txt"],
+ bazel_module: { bp2build_available: true },
+}
+EOF
+
+ INTEGRATED_BP2BUILD=1 run_soong
+ if [[ ! -e out/soong/bp2build/a/BUILD ]]; then
+ fail "a/BUILD not created";
+ fi
+
+ mkdir -p b
+ touch b/b.txt
+ cat > b/Android.bp <<'EOF'
+filegroup {
+ name: "b",
+ srcs: ["b.txt"],
+ bazel_module: { bp2build_available: true },
+}
+EOF
+
+ INTEGRATED_BP2BUILD=1 run_soong
+ if [[ ! -e out/soong/bp2build/b/BUILD ]]; then
+ fail "b/BUILD not created";
+ fi
+}
+
+function test_integrated_bp2build_null_build {
+ setup
+
+ INTEGRATED_BP2BUILD=1 run_soong
+ local mtime1=$(stat -c "%y" out/soong/build.ninja)
+
+ INTEGRATED_BP2BUILD=1 run_soong
+ local mtime2=$(stat -c "%y" out/soong/build.ninja)
+
+ if [[ "$mtime1" != "$mtime2" ]]; then
+ fail "Output Ninja file changed on null build"
+ fi
+}
+
+function test_integrated_bp2build_add_to_glob {
+ setup
+
+ mkdir -p a
+ touch a/a1.txt
+ cat > a/Android.bp <<'EOF'
+filegroup {
+ name: "a",
+ srcs: ["*.txt"],
+ bazel_module: { bp2build_available: true },
+}
+EOF
+
+ INTEGRATED_BP2BUILD=1 run_soong
+ grep -q a1.txt out/soong/bp2build/a/BUILD || fail "a1.txt not in BUILD file"
+
+ touch a/a2.txt
+ INTEGRATED_BP2BUILD=1 run_soong
+ grep -q a2.txt out/soong/bp2build/a/BUILD || fail "a2.txt not in BUILD file"
+}
+
+function test_dump_json_module_graph() {
+ setup
+ SOONG_DUMP_JSON_MODULE_GRAPH="$MOCK_TOP/modules.json" run_soong
+ if [[ ! -r "$MOCK_TOP/modules.json" ]]; then
+ fail "JSON file was not created"
+ fi
+}
+
+test_smoke
+test_null_build
+test_null_build_after_docs
+test_soong_build_rebuilt_if_blueprint_changes
+test_glob_noop_incremental
+test_add_file_to_glob
+test_add_android_bp
+test_change_android_bp
+test_delete_android_bp
+test_add_file_to_soong_build
+test_glob_during_bootstrapping
+test_soong_build_rerun_iff_environment_changes
+test_dump_json_module_graph
+test_integrated_bp2build_smoke
+test_integrated_bp2build_null_build
+test_integrated_bp2build_add_to_glob
diff --git a/tests/lib.sh b/tests/lib.sh
new file mode 100644
index 0000000..1478e37
--- /dev/null
+++ b/tests/lib.sh
@@ -0,0 +1,113 @@
+#!/bin/bash -eu
+
+HARDWIRED_MOCK_TOP=
+# Uncomment this to be able to view the source tree after a test is run
+# HARDWIRED_MOCK_TOP=/tmp/td
+
+REAL_TOP="$(readlink -f "$(dirname "$0")"/../../..)"
+
+if [[ ! -z "$HARDWIRED_MOCK_TOP" ]]; then
+ MOCK_TOP="$HARDWIRED_MOCK_TOP"
+else
+ MOCK_TOP=$(mktemp -t -d st.XXXXX)
+ trap cleanup_mock_top EXIT
+fi
+
+WARMED_UP_MOCK_TOP=$(mktemp -t soong_integration_tests_warmup.XXXXXX.tar.gz)
+trap 'rm -f "$WARMED_UP_MOCK_TOP"' EXIT
+
+function warmup_mock_top {
+ info "Warming up mock top ..."
+ info "Mock top warmup archive: $WARMED_UP_MOCK_TOP"
+ cleanup_mock_top
+ mkdir -p "$MOCK_TOP"
+ cd "$MOCK_TOP"
+
+ create_mock_soong
+ run_soong
+ tar czf "$WARMED_UP_MOCK_TOP" *
+}
+
+function cleanup_mock_top {
+ cd /
+ rm -fr "$MOCK_TOP"
+}
+
+function info {
+ echo -e "\e[92;1m[TEST HARNESS INFO]\e[0m" $*
+}
+
+function fail {
+ echo -e "\e[91;1mFAILED:\e[0m" $*
+ exit 1
+}
+
+function copy_directory() {
+ local dir="$1"
+ local parent="$(dirname "$dir")"
+
+ mkdir -p "$MOCK_TOP/$parent"
+ cp -R "$REAL_TOP/$dir" "$MOCK_TOP/$parent"
+}
+
+function symlink_file() {
+ local file="$1"
+
+ mkdir -p "$MOCK_TOP/$(dirname "$file")"
+ ln -s "$REAL_TOP/$file" "$MOCK_TOP/$file"
+}
+
+function symlink_directory() {
+ local dir="$1"
+
+ mkdir -p "$MOCK_TOP/$dir"
+ # We need to symlink the contents of the directory individually instead of
+ # using one symlink for the whole directory because finder.go doesn't follow
+ # symlinks when looking for Android.bp files
+ for i in $(ls "$REAL_TOP/$dir"); do
+ local target="$MOCK_TOP/$dir/$i"
+ local source="$REAL_TOP/$dir/$i"
+
+ if [[ -e "$target" ]]; then
+ if [[ ! -d "$source" || ! -d "$target" ]]; then
+ fail "Trying to symlink $dir twice"
+ fi
+ else
+ ln -s "$REAL_TOP/$dir/$i" "$MOCK_TOP/$dir/$i";
+ fi
+ done
+}
+
+function create_mock_soong {
+ copy_directory build/blueprint
+ copy_directory build/soong
+
+ symlink_directory prebuilts/go
+ symlink_directory prebuilts/build-tools
+ symlink_directory external/golang-protobuf
+
+ touch "$MOCK_TOP/Android.bp"
+}
+
+function setup() {
+ cleanup_mock_top
+ mkdir -p "$MOCK_TOP"
+
+ echo
+ echo ----------------------------------------------------------------------------
+ info "Running test case ${FUNCNAME[1]}"
+ cd "$MOCK_TOP"
+
+ tar xzf "$WARMED_UP_MOCK_TOP"
+}
+
+function run_soong() {
+ build/soong/soong_ui.bash --make-mode --skip-ninja --skip-make --skip-soong-tests
+}
+
+info "Starting Soong integration test suite $(basename $0)"
+info "Mock top: $MOCK_TOP"
+
+
+export ALLOW_MISSING_DEPENDENCIES=true
+warmup_mock_top
diff --git a/tests/mixed_mode_test.sh b/tests/mixed_mode_test.sh
new file mode 100755
index 0000000..7dbafea
--- /dev/null
+++ b/tests/mixed_mode_test.sh
@@ -0,0 +1,28 @@
+#!/bin/bash -eu
+
+# This test exercises mixed builds where Soong and Bazel cooperate in building
+# Android.
+#
+# When the execroot is deleted, the Bazel server process will automatically
+# terminate itself.
+
+source "$(dirname "$0")/lib.sh"
+
+function create_mock_bazel() {
+ copy_directory build/bazel
+
+ symlink_directory prebuilts/bazel
+ symlink_directory prebuilts/jdk
+
+ symlink_file WORKSPACE
+ symlink_file tools/bazel
+}
+
+function test_bazel_smoke {
+ setup
+ create_mock_bazel
+
+ tools/bazel info
+}
+
+test_bazel_smoke
diff --git a/tests/run_integration_tests.sh b/tests/run_integration_tests.sh
new file mode 100755
index 0000000..db24037
--- /dev/null
+++ b/tests/run_integration_tests.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+TOP="$(readlink -f "$(dirname "$0")"/../../..)"
+"$TOP/build/soong/tests/bootstrap_test.sh"
+"$TOP/build/soong/tests/mixed_mode_test.sh"
+
diff --git a/tradefed/autogen.go b/tradefed/autogen.go
index 27d71e8..3d96c84 100644
--- a/tradefed/autogen.go
+++ b/tradefed/autogen.go
@@ -245,6 +245,25 @@
return path
}
+func AutoGenRustBenchmarkConfig(ctx android.ModuleContext, testConfigProp *string,
+ testConfigTemplateProp *string, testSuites []string, config []Config, autoGenConfig *bool) android.Path {
+ path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
+ if autogenPath != nil {
+ templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
+ if templatePath.Valid() {
+ autogenTemplate(ctx, autogenPath, templatePath.String(), config, "")
+ } else {
+ if ctx.Device() {
+ autogenTemplate(ctx, autogenPath, "${RustDeviceBenchmarkConfigTemplate}", config, "")
+ } else {
+ autogenTemplate(ctx, autogenPath, "${RustHostBenchmarkConfigTemplate}", config, "")
+ }
+ }
+ return autogenPath
+ }
+ return path
+}
+
func AutoGenRobolectricTestConfig(ctx android.ModuleContext, testConfigProp *string, testConfigTemplateProp *string,
testSuites []string, autoGenConfig *bool) android.Path {
path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
diff --git a/tradefed/config.go b/tradefed/config.go
index f3566a8..999424c 100644
--- a/tradefed/config.go
+++ b/tradefed/config.go
@@ -34,6 +34,8 @@
pctx.SourcePathVariable("PythonBinaryHostTestConfigTemplate", "build/make/core/python_binary_host_test_config_template.xml")
pctx.SourcePathVariable("RustDeviceTestConfigTemplate", "build/make/core/rust_device_test_config_template.xml")
pctx.SourcePathVariable("RustHostTestConfigTemplate", "build/make/core/rust_host_test_config_template.xml")
+ pctx.SourcePathVariable("RustDeviceBenchmarkConfigTemplate", "build/make/core/rust_device_benchmark_config_template.xml")
+ pctx.SourcePathVariable("RustHostBenchmarkConfigTemplate", "build/make/core/rust_host_benchmark_config_template.xml")
pctx.SourcePathVariable("RobolectricTestConfigTemplate", "build/make/core/robolectric_test_config_template.xml")
pctx.SourcePathVariable("ShellTestConfigTemplate", "build/make/core/shell_test_config_template.xml")
diff --git a/tradefed/makevars.go b/tradefed/makevars.go
index f9682e4..9b5a20f 100644
--- a/tradefed/makevars.go
+++ b/tradefed/makevars.go
@@ -33,6 +33,8 @@
ctx.Strict("PYTHON_BINARY_HOST_TEST_CONFIG_TEMPLATE", "${PythonBinaryHostTestConfigTemplate}")
ctx.Strict("RUST_DEVICE_TEST_CONFIG_TEMPLATE", "${RustDeviceTestConfigTemplate}")
ctx.Strict("RUST_HOST_TEST_CONFIG_TEMPLATE", "${RustHostTestConfigTemplate}")
+ ctx.Strict("RUST_DEVICE_BENCHMARK_CONFIG_TEMPLATE", "${RustDeviceBenchmarkConfigTemplate}")
+ ctx.Strict("RUST_HOST_BENCHMARK_CONFIG_TEMPLATE", "${RustHostBenchmarkConfigTemplate}")
ctx.Strict("SHELL_TEST_CONFIG_TEMPLATE", "${ShellTestConfigTemplate}")
ctx.Strict("EMPTY_TEST_CONFIG", "${EmptyTestConfig}")
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 9afcb88..7e94b25 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -21,6 +21,7 @@
"strconv"
"android/soong/shared"
+ "github.com/google/blueprint/deptools"
soong_metrics_proto "android/soong/ui/metrics/metrics_proto"
"github.com/google/blueprint"
@@ -33,6 +34,11 @@
"android/soong/ui/status"
)
+const (
+ availableEnvFile = "soong.environment.available"
+ usedEnvFile = "soong.environment.used"
+)
+
func writeEnvironmentFile(ctx Context, envFile string, envDeps map[string]string) error {
data, err := shared.EnvFileContents(envDeps)
if err != nil {
@@ -87,12 +93,23 @@
return c.debugCompilation
}
-func bootstrapBlueprint(ctx Context, config Config) {
+func environmentArgs(config Config, suffix string) []string {
+ return []string{
+ "--available_env", shared.JoinPath(config.SoongOutDir(), availableEnvFile),
+ "--used_env", shared.JoinPath(config.SoongOutDir(), usedEnvFile+suffix),
+ }
+}
+func bootstrapBlueprint(ctx Context, config Config, integratedBp2Build bool) {
ctx.BeginTrace(metrics.RunSoong, "blueprint bootstrap")
defer ctx.EndTrace()
var args bootstrap.Args
+ mainNinjaFile := shared.JoinPath(config.SoongOutDir(), "build.ninja")
+ globFile := shared.JoinPath(config.SoongOutDir(), ".bootstrap/soong-build-globs.ninja")
+ bootstrapGlobFile := shared.JoinPath(config.SoongOutDir(), ".bootstrap/build-globs.ninja")
+ bootstrapDepFile := shared.JoinPath(config.SoongOutDir(), ".bootstrap/build.ninja.d")
+
args.RunGoTests = !config.skipSoongTests
args.UseValidations = true // Use validations to depend on tests
args.BuildDir = config.SoongOutDir()
@@ -100,10 +117,52 @@
args.TopFile = "Android.bp"
args.ModuleListFile = filepath.Join(config.FileListDir(), "Android.bp.list")
args.OutFile = shared.JoinPath(config.SoongOutDir(), ".bootstrap/build.ninja")
- args.DepFile = shared.JoinPath(config.SoongOutDir(), ".bootstrap/build.ninja.d")
- args.GlobFile = shared.JoinPath(config.SoongOutDir(), ".bootstrap/soong-build-globs.ninja")
+ args.GlobFile = globFile
args.GeneratingPrimaryBuilder = true
+ args.DelveListen = os.Getenv("SOONG_DELVE")
+ if args.DelveListen != "" {
+ args.DelvePath = shared.ResolveDelveBinary()
+ }
+
+ commonArgs := bootstrap.PrimaryBuilderExtraFlags(args, bootstrapGlobFile, mainNinjaFile)
+ bp2BuildMarkerFile := shared.JoinPath(config.SoongOutDir(), ".bootstrap/bp2build_workspace_marker")
+ mainSoongBuildInputs := []string{"Android.bp"}
+
+ if integratedBp2Build {
+ mainSoongBuildInputs = append(mainSoongBuildInputs, bp2BuildMarkerFile)
+ }
+
+ soongBuildArgs := make([]string, 0)
+ soongBuildArgs = append(soongBuildArgs, commonArgs...)
+ soongBuildArgs = append(soongBuildArgs, environmentArgs(config, "")...)
+ soongBuildArgs = append(soongBuildArgs, "Android.bp")
+
+ mainSoongBuildInvocation := bootstrap.PrimaryBuilderInvocation{
+ Inputs: mainSoongBuildInputs,
+ Outputs: []string{mainNinjaFile},
+ Args: soongBuildArgs,
+ }
+
+ if integratedBp2Build {
+ bp2buildArgs := []string{"--bp2build_marker", bp2BuildMarkerFile}
+ bp2buildArgs = append(bp2buildArgs, commonArgs...)
+ bp2buildArgs = append(bp2buildArgs, environmentArgs(config, ".bp2build")...)
+ bp2buildArgs = append(bp2buildArgs, "Android.bp")
+
+ bp2buildInvocation := bootstrap.PrimaryBuilderInvocation{
+ Inputs: []string{"Android.bp"},
+ Outputs: []string{bp2BuildMarkerFile},
+ Args: bp2buildArgs,
+ }
+ args.PrimaryBuilderInvocations = []bootstrap.PrimaryBuilderInvocation{
+ bp2buildInvocation,
+ mainSoongBuildInvocation,
+ }
+ } else {
+ args.PrimaryBuilderInvocations = []bootstrap.PrimaryBuilderInvocation{mainSoongBuildInvocation}
+ }
+
blueprintCtx := blueprint.NewContext()
blueprintCtx.SetIgnoreUnknownModuleTypes(true)
blueprintConfig := BlueprintConfig{
@@ -113,7 +172,21 @@
debugCompilation: os.Getenv("SOONG_DELVE") != "",
}
- bootstrap.RunBlueprint(args, blueprintCtx, blueprintConfig)
+ bootstrapDeps := bootstrap.RunBlueprint(args, blueprintCtx, blueprintConfig)
+ err := deptools.WriteDepFile(bootstrapDepFile, args.OutFile, bootstrapDeps)
+ if err != nil {
+ ctx.Fatalf("Error writing depfile '%s': %s", bootstrapDepFile, err)
+ }
+}
+
+func checkEnvironmentFile(currentEnv *Environment, envFile string) {
+ getenv := func(k string) string {
+ v, _ := currentEnv.Get(k)
+ return v
+ }
+ if stale, _ := shared.StaleEnvFile(envFile, getenv); stale {
+ os.Remove(envFile)
+ }
}
func runSoong(ctx Context, config Config) {
@@ -124,7 +197,7 @@
// .used with the ones that were actually used. The latter is used to
// determine whether Soong needs to be re-run since why re-run it if only
// unused variables were changed?
- envFile := filepath.Join(config.SoongOutDir(), "soong.environment.available")
+ envFile := filepath.Join(config.SoongOutDir(), availableEnvFile)
for _, n := range []string{".bootstrap", ".minibootstrap"} {
dir := filepath.Join(config.SoongOutDir(), n)
@@ -133,16 +206,13 @@
}
}
+ integratedBp2Build := config.Environment().IsEnvTrue("INTEGRATED_BP2BUILD")
+
// This is done unconditionally, but does not take a measurable amount of time
- bootstrapBlueprint(ctx, config)
+ bootstrapBlueprint(ctx, config, integratedBp2Build)
soongBuildEnv := config.Environment().Copy()
soongBuildEnv.Set("TOP", os.Getenv("TOP"))
- // These two dependencies are read from bootstrap.go, but also need to be here
- // so that soong_build can declare a dependency on them
- soongBuildEnv.Set("SOONG_DELVE", os.Getenv("SOONG_DELVE"))
- soongBuildEnv.Set("SOONG_DELVE_PATH", os.Getenv("SOONG_DELVE_PATH"))
- soongBuildEnv.Set("SOONG_OUTDIR", config.SoongOutDir())
// For Bazel mixed builds.
soongBuildEnv.Set("BAZEL_PATH", "./tools/bazel")
soongBuildEnv.Set("BAZEL_HOME", filepath.Join(config.BazelOutDir(), "bazelhome"))
@@ -164,13 +234,12 @@
ctx.BeginTrace(metrics.RunSoong, "environment check")
defer ctx.EndTrace()
- envFile := filepath.Join(config.SoongOutDir(), "soong.environment.used")
- getenv := func(k string) string {
- v, _ := soongBuildEnv.Get(k)
- return v
- }
- if stale, _ := shared.StaleEnvFile(envFile, getenv); stale {
- os.Remove(envFile)
+ soongBuildEnvFile := filepath.Join(config.SoongOutDir(), usedEnvFile)
+ checkEnvironmentFile(soongBuildEnv, soongBuildEnvFile)
+
+ if integratedBp2Build {
+ bp2buildEnvFile := filepath.Join(config.SoongOutDir(), usedEnvFile+".bp2build")
+ checkEnvironmentFile(soongBuildEnv, bp2buildEnvFile)
}
}()
@@ -215,13 +284,6 @@
// This is currently how the command line to invoke soong_build finds the
// root of the source tree and the output root
ninjaEnv.Set("TOP", os.Getenv("TOP"))
- ninjaEnv.Set("SOONG_OUTDIR", config.SoongOutDir())
-
- // For debugging
- if os.Getenv("SOONG_DELVE") != "" {
- ninjaEnv.Set("SOONG_DELVE", os.Getenv("SOONG_DELVE"))
- ninjaEnv.Set("SOONG_DELVE_PATH", shared.ResolveDelveBinary())
- }
cmd.Environment = &ninjaEnv
cmd.Sandbox = soongSandbox
diff --git a/zip/zip.go b/zip/zip.go
index a6490d4..84e974b 100644
--- a/zip/zip.go
+++ b/zip/zip.go
@@ -292,11 +292,11 @@
continue
}
- globbed, _, err := z.fs.Glob(s, nil, followSymlinks)
+ result, err := z.fs.Glob(s, nil, followSymlinks)
if err != nil {
return err
}
- if len(globbed) == 0 {
+ if len(result.Matches) == 0 {
err := &os.PathError{
Op: "lstat",
Path: s,
@@ -308,7 +308,7 @@
return err
}
}
- srcs = append(srcs, globbed...)
+ srcs = append(srcs, result.Matches...)
}
if fa.GlobDir != "" {
if exists, isDir, err := z.fs.Exists(fa.GlobDir); err != nil {
@@ -336,11 +336,11 @@
return err
}
}
- globbed, _, err := z.fs.Glob(filepath.Join(fa.GlobDir, "**/*"), nil, followSymlinks)
+ result, err := z.fs.Glob(filepath.Join(fa.GlobDir, "**/*"), nil, followSymlinks)
if err != nil {
return err
}
- srcs = append(srcs, globbed...)
+ srcs = append(srcs, result.Matches...)
}
for _, src := range srcs {
err := fillPathPairs(fa, src, &pathMappings, args.NonDeflatedFiles, noCompression)