diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go index 8ab0134b2..81590a597 100644 --- a/cc/snapshot_prebuilt.go +++ b/cc/snapshot_prebuilt.go @@ -120,6 +120,10 @@ func (vendorSnapshotImage) Init(ctx android.RegistrationContext) { ctx.RegisterSingletonType("vendor-fake-snapshot", VendorFakeSnapshotSingleton) } +func (vendorSnapshotImage) RegisterAdditionalModule(ctx android.RegistrationContext, name string, factory android.ModuleFactory) { + ctx.RegisterModuleType(name, factory) +} + func (vendorSnapshotImage) shouldGenerateSnapshot(ctx android.SingletonContext) bool { // BOARD_VNDK_VERSION must be set to 'current' in order to generate a snapshot. return ctx.DeviceConfig().VndkVersion() == "current" @@ -268,12 +272,14 @@ const ( SnapshotStaticSuffix = "_static." snapshotBinarySuffix = "_binary." snapshotObjectSuffix = "_object." + SnapshotRlibSuffix = "_rlib." ) type SnapshotProperties struct { Header_libs []string `android:"arch_variant"` Static_libs []string `android:"arch_variant"` Shared_libs []string `android:"arch_variant"` + Rlibs []string `android:"arch_variant"` Vndk_libs []string `android:"arch_variant"` Binaries []string `android:"arch_variant"` Objects []string `android:"arch_variant"` @@ -353,6 +359,7 @@ func (s *snapshot) DepsMutator(ctx android.BottomUpMutatorContext) { objects := collectSnapshotMap(s.properties.Objects, snapshotSuffix, snapshotObjectSuffix) staticLibs := collectSnapshotMap(s.properties.Static_libs, snapshotSuffix, SnapshotStaticSuffix) sharedLibs := collectSnapshotMap(s.properties.Shared_libs, snapshotSuffix, SnapshotSharedSuffix) + rlibs := collectSnapshotMap(s.properties.Rlibs, snapshotSuffix, SnapshotRlibSuffix) vndkLibs := collectSnapshotMap(s.properties.Vndk_libs, "", vndkSuffix) for k, v := range vndkLibs { sharedLibs[k] = v @@ -364,11 +371,12 @@ func (s *snapshot) DepsMutator(ctx android.BottomUpMutatorContext) { Objects: objects, StaticLibs: staticLibs, SharedLibs: sharedLibs, + Rlibs: rlibs, }) } type SnapshotInfo struct { - HeaderLibs, Binaries, Objects, StaticLibs, SharedLibs map[string]string + HeaderLibs, Binaries, Objects, StaticLibs, SharedLibs, Rlibs map[string]string } var SnapshotInfoProvider = blueprint.NewMutatorProvider(SnapshotInfo{}, "deps") diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go index 04aab4245..5a303c806 100644 --- a/cc/vendor_snapshot.go +++ b/cc/vendor_snapshot.go @@ -205,7 +205,7 @@ func isSnapshotAware(cfg android.DeviceConfig, m LinkableInterface, inProprietar if sanitizable.Static() { return sanitizable.OutputFile().Valid() && !image.private(m) } - if sanitizable.Shared() { + if sanitizable.Shared() || sanitizable.Rlib() { if !sanitizable.OutputFile().Valid() { return false } @@ -393,6 +393,8 @@ func (c *snapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) { libType = "static" } else if m.Shared() { libType = "shared" + } else if m.Rlib() { + libType = "rlib" } else { libType = "header" } @@ -404,7 +406,7 @@ func (c *snapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) { libPath := m.OutputFile().Path() stem = libPath.Base() if sanitizable, ok := m.(PlatformSanitizeable); ok { - if sanitizable.Static() && sanitizable.SanitizePropDefined() && sanitizable.IsSanitizerEnabled(cfi) { + if (sanitizable.Static() || sanitizable.Rlib()) && sanitizable.SanitizePropDefined() && sanitizable.IsSanitizerEnabled(cfi) { // both cfi and non-cfi variant for static libraries can exist. // attach .cfi to distinguish between cfi and non-cfi. // e.g. libbase.a -> libbase.cfi.a diff --git a/rust/Android.bp b/rust/Android.bp index 63983904c..11069d143 100644 --- a/rust/Android.bp +++ b/rust/Android.bp @@ -32,6 +32,7 @@ bootstrap_go_package { "rust.go", "sanitize.go", "source_provider.go", + "snapshot_prebuilt.go", "snapshot_utils.go", "strip.go", "test.go", diff --git a/rust/image.go b/rust/image.go index 6cfb42c7d..3b54f12c7 100644 --- a/rust/image.go +++ b/rust/image.go @@ -82,7 +82,12 @@ func (mod *Module) SetCoreVariantNeeded(b bool) { } func (mod *Module) SnapshotVersion(mctx android.BaseModuleContext) string { - panic("Rust modules do not support snapshotting: " + mod.BaseModuleName()) + if snapshot, ok := mod.compiler.(cc.SnapshotInterface); ok { + return snapshot.Version() + } else { + mctx.ModuleErrorf("version is unknown for snapshot prebuilt") + return "" + } } func (mod *Module) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { @@ -110,7 +115,9 @@ func (mod *Module) ExtraImageVariations(android.BaseModuleContext) []string { } func (mod *Module) IsSnapshotPrebuilt() bool { - // Rust does not support prebuilts in its snapshots + if p, ok := mod.compiler.(cc.SnapshotInterface); ok { + return p.IsSnapshotPrebuilt() + } return false } @@ -220,7 +227,9 @@ func (mod *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { } } if vendorSpecific { - mctx.PropertyErrorf("vendor", "Vendor-only non-rust_ffi Rust modules are not supported.") + if lib, ok := mod.compiler.(libraryInterface); ok && lib.buildDylib() { + mctx.PropertyErrorf("vendor", "Vendor-only dylibs are not yet supported, use rust_library_rlib.") + } } cc.MutateImage(mctx, mod) diff --git a/rust/library.go b/rust/library.go index 7421817cc..1a56ef6c1 100644 --- a/rust/library.go +++ b/rust/library.go @@ -124,7 +124,8 @@ type libraryInterface interface { setStatic() setSource() - // Set libstd linkage + // libstd linkage functions + rlibStd() bool setRlibStd() setDylibStd() @@ -195,6 +196,10 @@ func (library *libraryDecorator) setDylib() { library.MutatedProperties.VariantIsShared = false } +func (library *libraryDecorator) rlibStd() bool { + return library.MutatedProperties.VariantIsStaticStd +} + func (library *libraryDecorator) setRlibStd() { library.MutatedProperties.VariantIsStaticStd = true } @@ -680,9 +685,10 @@ func LibstdMutator(mctx android.BottomUpMutatorContext) { dylib := modules[1].(*Module) rlib.compiler.(libraryInterface).setRlibStd() dylib.compiler.(libraryInterface).setDylibStd() - if dylib.ModuleBase.ImageVariation().Variation == android.VendorRamdiskVariation { + if dylib.ModuleBase.ImageVariation().Variation == android.VendorRamdiskVariation || + strings.HasPrefix(dylib.ModuleBase.ImageVariation().Variation, cc.VendorVariationPrefix) { // TODO(b/165791368) - // Disable rlibs that link against dylib-std on vendor ramdisk variations until those dylib + // Disable rlibs that link against dylib-std on vendor and vendor ramdisk variations until those dylib // variants are properly supported. dylib.Disable() } diff --git a/rust/rust.go b/rust/rust.go index 7a8687c8b..b8c8be5a2 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -1209,10 +1209,14 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) { } // rlibs - actx.AddVariationDependencies( - append(rlibDepVariations, []blueprint.Variation{ - {Mutator: "rust_libraries", Variation: rlibVariation}}...), - rlibDepTag, deps.Rlibs...) + for _, lib := range deps.Rlibs { + depTag := rlibDepTag + lib = cc.RewriteSnapshotLib(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).Rlibs) + + actx.AddVariationDependencies(append(rlibDepVariations, []blueprint.Variation{ + {Mutator: "rust_libraries", Variation: rlibVariation}, + }...), depTag, lib) + } // dylibs actx.AddVariationDependencies( @@ -1224,9 +1228,13 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) { if deps.Rustlibs != nil && !mod.compiler.Disabled() { autoDep := mod.compiler.(autoDeppable).autoDep(ctx) if autoDep.depTag == rlibDepTag { - actx.AddVariationDependencies( - append(rlibDepVariations, blueprint.Variation{Mutator: "rust_libraries", Variation: autoDep.variation}), - autoDep.depTag, deps.Rustlibs...) + for _, lib := range deps.Rustlibs { + depTag := autoDep.depTag + lib = cc.RewriteSnapshotLib(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).Rlibs) + actx.AddVariationDependencies(append(rlibDepVariations, []blueprint.Variation{ + {Mutator: "rust_libraries", Variation: autoDep.variation}, + }...), depTag, lib) + } } else { actx.AddVariationDependencies( append(commonDepVariations, blueprint.Variation{Mutator: "rust_libraries", Variation: autoDep.variation}), @@ -1237,9 +1245,13 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) { // stdlibs if deps.Stdlibs != nil { if mod.compiler.stdLinkage(ctx) == RlibLinkage { - actx.AddVariationDependencies( - append(commonDepVariations, []blueprint.Variation{{Mutator: "rust_libraries", Variation: "rlib"}}...), - rlibDepTag, deps.Stdlibs...) + for _, lib := range deps.Stdlibs { + depTag := rlibDepTag + lib = cc.RewriteSnapshotLib(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).Rlibs) + + actx.AddVariationDependencies(append(commonDepVariations, []blueprint.Variation{{Mutator: "rust_libraries", Variation: "rlib"}}...), + depTag, lib) + } } else { actx.AddVariationDependencies( append(commonDepVariations, blueprint.Variation{Mutator: "rust_libraries", Variation: "dylib"}), diff --git a/rust/rust_test.go b/rust/rust_test.go index f07f86bf8..80f693eb6 100644 --- a/rust/rust_test.go +++ b/rust/rust_test.go @@ -59,6 +59,7 @@ var rustMockedFiles = android.MockFS{ "liby.so": nil, "libz.so": nil, "data.txt": nil, + "liblog.map.txt": nil, } // testRust returns a TestContext in which a basic environment has been setup. @@ -77,18 +78,25 @@ func testRustVndk(t *testing.T, bp string) *android.TestContext { return testRustVndkFs(t, bp, rustMockedFiles) } -const vendorVariant = "android_vendor.29_arm64_armv8-a_shared" +const ( + sharedVendorVariant = "android_vendor.29_arm64_armv8-a_shared" + rlibVendorVariant = "android_vendor.29_arm64_armv8-a_rlib_rlib-std" +) func testRustVndkFs(t *testing.T, bp string, fs android.MockFS) *android.TestContext { + return testRustVndkFsVersions(t, bp, fs, "current", "current", "29") +} + +func testRustVndkFsVersions(t *testing.T, bp string, fs android.MockFS, device_version, product_version, vndk_version string) *android.TestContext { skipTestIfOsNotSupported(t) result := android.GroupFixturePreparers( prepareForRustTest, fs.AddToFixture(), android.FixtureModifyProductVariables( func(variables android.FixtureProductVariables) { - variables.DeviceVndkVersion = StringPtr("current") - variables.ProductVndkVersion = StringPtr("current") - variables.Platform_vndk_version = StringPtr("29") + variables.DeviceVndkVersion = StringPtr(device_version) + variables.ProductVndkVersion = StringPtr(product_version) + variables.Platform_vndk_version = StringPtr(vndk_version) }, ), ).RunTestWithBp(t, bp) diff --git a/rust/snapshot_prebuilt.go b/rust/snapshot_prebuilt.go new file mode 100644 index 000000000..2f549738c --- /dev/null +++ b/rust/snapshot_prebuilt.go @@ -0,0 +1,121 @@ +// Copyright 2021 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rust + +import ( + "android/soong/android" + "android/soong/cc" + "github.com/google/blueprint/proptools" +) + +const ( + snapshotRlibSuffix = "_rlib." +) + +type snapshotLibraryDecorator struct { + cc.BaseSnapshotDecorator + *libraryDecorator + properties cc.SnapshotLibraryProperties + sanitizerProperties struct { + CfiEnabled bool `blueprint:"mutated"` + + // Library flags for cfi variant. + Cfi cc.SnapshotLibraryProperties `android:"arch_variant"` + } +} + +func init() { + registerRustSnapshotModules(android.InitRegistrationContext) +} + +func registerRustSnapshotModules(ctx android.RegistrationContext) { + cc.VendorSnapshotImageSingleton.RegisterAdditionalModule(ctx, + "vendor_snapshot_rlib", VendorSnapshotRlibFactory) +} + +func snapshotLibraryFactory(image cc.SnapshotImage, moduleSuffix string) (*Module, *snapshotLibraryDecorator) { + module, library := NewRustLibrary(android.DeviceSupported) + + module.sanitize = nil + library.stripper.StripProperties.Strip.None = proptools.BoolPtr(true) + + prebuilt := &snapshotLibraryDecorator{ + libraryDecorator: library, + } + + module.compiler = prebuilt + + prebuilt.Init(module, image, moduleSuffix) + module.AddProperties( + &prebuilt.properties, + &prebuilt.sanitizerProperties, + ) + + return module, prebuilt +} + +func (library *snapshotLibraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path { + var variant string + if library.static() { + variant = cc.SnapshotStaticSuffix + } else if library.shared() { + variant = cc.SnapshotSharedSuffix + } else if library.rlib() { + variant = cc.SnapshotRlibSuffix + } + + if !library.dylib() { + // TODO(184042776): Remove this check when dylibs are supported in snapshots. + library.SetSnapshotAndroidMkSuffix(ctx, variant) + } + + if !library.MatchesWithDevice(ctx.DeviceConfig()) { + return nil + } + + return android.PathForModuleSrc(ctx, *library.properties.Src) +} + +func (library *snapshotLibraryDecorator) rustdoc(ctx ModuleContext, flags Flags, deps PathDeps) android.OptionalPath { + return android.OptionalPath{} +} + +// vendor_snapshot_rlib is a special prebuilt rlib library which is auto-generated by +// development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_rlib +// overrides the vendor variant of the rust rlib library with the same name, if BOARD_VNDK_VERSION +// is set. +func VendorSnapshotRlibFactory() android.Module { + module, prebuilt := snapshotLibraryFactory(cc.VendorSnapshotImageSingleton, cc.SnapshotRlibSuffix) + prebuilt.libraryDecorator.BuildOnlyRlib() + prebuilt.libraryDecorator.setNoStdlibs() + return module.Init() +} + +func (library *snapshotLibraryDecorator) MatchesWithDevice(config android.DeviceConfig) bool { + arches := config.Arches() + if len(arches) == 0 || arches[0].ArchType.String() != library.Arch() { + return false + } + if library.properties.Src == nil { + return false + } + return true +} + +func (library *snapshotLibraryDecorator) IsSnapshotPrebuilt() bool { + return true +} + +var _ cc.SnapshotInterface = (*snapshotLibraryDecorator)(nil) diff --git a/rust/snapshot_utils.go b/rust/snapshot_utils.go index 9d5154ce2..bd7ca7f68 100644 --- a/rust/snapshot_utils.go +++ b/rust/snapshot_utils.go @@ -42,9 +42,8 @@ func (mod *Module) ExcludeFromRecoverySnapshot() bool { func (mod *Module) IsSnapshotLibrary() bool { if lib, ok := mod.compiler.(libraryInterface); ok { - // Rust-native dylibs and rlibs are not snapshot supported yet, so only - // return true if this module produces a C shared or static library. - return lib.shared() || lib.static() + // Rust-native dylibs are not snapshot supported yet. Only snapshot the rlib-std variants of rlibs. + return lib.shared() || lib.static() || (lib.rlib() && lib.rlibStd()) } return false } diff --git a/rust/testing.go b/rust/testing.go index a7cbf54d8..72f87e136 100644 --- a/rust/testing.go +++ b/rust/testing.go @@ -135,6 +135,9 @@ func GatherRequiredDepsForTest() string { apex_available: ["//apex_available:platform", "//apex_available:anyapex"], min_sdk_version: "29", vendor_available: true, + llndk: { + symbol_file: "liblog.map.txt", + }, } cc_library { name: "libprotobuf-cpp-full", @@ -245,4 +248,5 @@ func registerRequiredBuildComponentsForTest(ctx android.RegistrationContext) { ctx.BottomUp("rust_begin", BeginMutator).Parallel() }) ctx.RegisterSingletonType("rust_project_generator", rustProjectGeneratorSingleton) + registerRustSnapshotModules(ctx) } diff --git a/rust/vendor_snapshot_test.go b/rust/vendor_snapshot_test.go index c5183f754..815f80ec7 100644 --- a/rust/vendor_snapshot_test.go +++ b/rust/vendor_snapshot_test.go @@ -17,6 +17,7 @@ package rust import ( "fmt" "path/filepath" + "reflect" "strings" "testing" @@ -27,6 +28,22 @@ import ( func TestVendorSnapshotCapture(t *testing.T) { bp := ` rust_ffi { + name: "libffivendor_available", + crate_name: "ffivendor_available", + srcs: ["lib.rs"], + vendor_available: true, + include_dirs: ["rust_headers/"], + } + + rust_ffi { + name: "libffivendor", + crate_name: "ffivendor", + srcs: ["lib.rs"], + vendor: true, + include_dirs: ["rust_headers/"], + } + + rust_library { name: "librustvendor_available", crate_name: "rustvendor_available", srcs: ["lib.rs"], @@ -34,13 +51,26 @@ func TestVendorSnapshotCapture(t *testing.T) { include_dirs: ["rust_headers/"], } + rust_library_rlib { + name: "librustvendor", + crate_name: "rustvendor", + srcs: ["lib.rs"], + vendor: true, + include_dirs: ["rust_headers/"], + } + rust_binary { name: "vendor_available_bin", vendor_available: true, srcs: ["srcs/lib.rs"], } -` + rust_binary { + name: "vendor_bin", + vendor: true, + srcs: ["srcs/lib.rs"], + } + ` skipTestIfOsNotSupported(t) result := android.GroupFixturePreparers( prepareForRustTest, @@ -71,24 +101,40 @@ func TestVendorSnapshotCapture(t *testing.T) { // For shared libraries, only non-VNDK vendor_available modules are captured sharedVariant := fmt.Sprintf("android_vendor.29_%s_%s_shared", archType, archVariant) sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") - cc.CheckSnapshot(t, ctx, snapshotSingleton, "librustvendor_available", "librustvendor_available.so", sharedDir, sharedVariant) + cc.CheckSnapshot(t, ctx, snapshotSingleton, "libffivendor_available", "libffivendor_available.so", sharedDir, sharedVariant) jsonFiles = append(jsonFiles, - filepath.Join(sharedDir, "librustvendor_available.so.json")) + filepath.Join(sharedDir, "libffivendor_available.so.json")) // For static libraries, all vendor:true and vendor_available modules (including VNDK) are captured. staticVariant := fmt.Sprintf("android_vendor.29_%s_%s_static", archType, archVariant) staticDir := filepath.Join(snapshotVariantPath, archDir, "static") - cc.CheckSnapshot(t, ctx, snapshotSingleton, "librustvendor_available", "librustvendor_available.a", staticDir, staticVariant) + cc.CheckSnapshot(t, ctx, snapshotSingleton, "libffivendor_available", "libffivendor_available.a", staticDir, staticVariant) + cc.CheckSnapshot(t, ctx, snapshotSingleton, "libffivendor", "libffivendor.a", staticDir, staticVariant) jsonFiles = append(jsonFiles, - filepath.Join(staticDir, "librustvendor_available.a.json")) + filepath.Join(staticDir, "libffivendor_available.a.json")) + jsonFiles = append(jsonFiles, + filepath.Join(staticDir, "libffivendor.a.json")) - // For binary executables, all vendor_available modules are captured. + // For rlib libraries, all vendor:true and vendor_available modules (including VNDK) are captured. + rlibVariant := fmt.Sprintf("android_vendor.29_%s_%s_rlib_rlib-std", archType, archVariant) + rlibDir := filepath.Join(snapshotVariantPath, archDir, "rlib") + cc.CheckSnapshot(t, ctx, snapshotSingleton, "librustvendor_available", "librustvendor_available.rlib", rlibDir, rlibVariant) + cc.CheckSnapshot(t, ctx, snapshotSingleton, "librustvendor", "librustvendor.rlib", rlibDir, rlibVariant) + jsonFiles = append(jsonFiles, + filepath.Join(rlibDir, "librustvendor_available.rlib.json")) + jsonFiles = append(jsonFiles, + filepath.Join(rlibDir, "librustvendor.rlib.json")) + + // For binary executables, all vendor:true and vendor_available modules are captured. if archType == "arm64" { binaryVariant := fmt.Sprintf("android_vendor.29_%s_%s", archType, archVariant) binaryDir := filepath.Join(snapshotVariantPath, archDir, "binary") cc.CheckSnapshot(t, ctx, snapshotSingleton, "vendor_available_bin", "vendor_available_bin", binaryDir, binaryVariant) + cc.CheckSnapshot(t, ctx, snapshotSingleton, "vendor_bin", "vendor_bin", binaryDir, binaryVariant) jsonFiles = append(jsonFiles, filepath.Join(binaryDir, "vendor_available_bin.json")) + jsonFiles = append(jsonFiles, + filepath.Join(binaryDir, "vendor_bin.json")) } } @@ -113,6 +159,13 @@ func TestVendorSnapshotCapture(t *testing.T) { func TestVendorSnapshotDirected(t *testing.T) { bp := ` rust_ffi_shared { + name: "libffivendor_available", + crate_name: "ffivendor_available", + srcs: ["lib.rs"], + vendor_available: true, + } + + rust_library { name: "librustvendor_available", crate_name: "rustvendor_available", srcs: ["lib.rs"], @@ -120,6 +173,13 @@ func TestVendorSnapshotDirected(t *testing.T) { } rust_ffi_shared { + name: "libffivendor_exclude", + crate_name: "ffivendor_exclude", + srcs: ["lib.rs"], + vendor_available: true, + } + + rust_library { name: "librustvendor_exclude", crate_name: "rustvendor_exclude", srcs: ["lib.rs"], @@ -129,6 +189,7 @@ func TestVendorSnapshotDirected(t *testing.T) { ctx := testRustVndk(t, bp) ctx.Config().TestProductVariables.VendorSnapshotModules = make(map[string]bool) ctx.Config().TestProductVariables.VendorSnapshotModules["librustvendor_available"] = true + ctx.Config().TestProductVariables.VendorSnapshotModules["libffivendor_available"] = true ctx.Config().TestProductVariables.DirectedVendorSnapshot = true // Check Vendor snapshot output. @@ -148,16 +209,22 @@ func TestVendorSnapshotDirected(t *testing.T) { archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant) sharedVariant := fmt.Sprintf("android_vendor.29_%s_%s_shared", archType, archVariant) + rlibVariant := fmt.Sprintf("android_vendor.29_%s_%s_rlib_rlib-std", archType, archVariant) sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") + rlibDir := filepath.Join(snapshotVariantPath, archDir, "rlib") // Included modules - cc.CheckSnapshot(t, ctx, snapshotSingleton, "librustvendor_available", "librustvendor_available.so", sharedDir, sharedVariant) - includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "librustvendor_available.so.json")) + cc.CheckSnapshot(t, ctx, snapshotSingleton, "librustvendor_available", "librustvendor_available.rlib", rlibDir, rlibVariant) + cc.CheckSnapshot(t, ctx, snapshotSingleton, "libffivendor_available", "libffivendor_available.so", sharedDir, sharedVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librustvendor_available.rlib.json")) + includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libffivendor_available.so.json")) // Excluded modules. Modules not included in the directed vendor snapshot // are still include as fake modules. - cc.CheckSnapshotRule(t, ctx, snapshotSingleton, "librustvendor_exclude", "librustvendor_exclude.so", sharedDir, sharedVariant) - includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "librustvendor_exclude.so.json")) + cc.CheckSnapshotRule(t, ctx, snapshotSingleton, "librustvendor_exclude", "librustvendor_exclude.rlib", rlibDir, rlibVariant) + cc.CheckSnapshotRule(t, ctx, snapshotSingleton, "libffivendor_exclude", "libffivendor_exclude.so", sharedDir, sharedVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librustvendor_exclude.rlib.json")) + includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libffivendor_exclude.so.json")) } // Verify that each json file for an included module has a rule. @@ -176,10 +243,6 @@ func TestVendorSnapshotExclude(t *testing.T) { // excluded in the vendor snapshot based on their path (framework or // vendor) and the exclude_from_vendor_snapshot property. - // When vendor-specific Rust modules are available, make sure to test - // that they're excluded by path here. See cc.TestVendorSnapshotExclude - // for an example. - frameworkBp := ` rust_ffi_shared { name: "libinclude", @@ -192,7 +255,7 @@ func TestVendorSnapshotExclude(t *testing.T) { name: "libexclude", crate_name: "exclude", srcs: ["exclude.rs"], - vendor_available: true, + vendor: true, exclude_from_vendor_snapshot: true, } @@ -203,6 +266,29 @@ func TestVendorSnapshotExclude(t *testing.T) { vendor_available: true, exclude_from_vendor_snapshot: true, } + + rust_library { + name: "librust_include", + crate_name: "rust_include", + srcs: ["include.rs"], + vendor_available: true, + } + + rust_library_rlib { + name: "librust_exclude", + crate_name: "rust_exclude", + srcs: ["exclude.rs"], + vendor: true, + exclude_from_vendor_snapshot: true, + } + + rust_library { + name: "librust_available_exclude", + crate_name: "rust_available_exclude", + srcs: ["lib.rs"], + vendor_available: true, + exclude_from_vendor_snapshot: true, + } ` mockFS := map[string][]byte{ @@ -214,9 +300,13 @@ func TestVendorSnapshotExclude(t *testing.T) { ctx := testRustVndkFs(t, "", mockFS) // Test an include and exclude framework module. - cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "libinclude", false, vendorVariant) - cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "libexclude", true, vendorVariant) - cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "libavailable_exclude", true, vendorVariant) + cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "libinclude", false, sharedVendorVariant) + cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "libexclude", true, sharedVendorVariant) + cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "libavailable_exclude", true, sharedVendorVariant) + + cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "librust_include", false, rlibVendorVariant) + cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "librust_exclude", true, rlibVendorVariant) + cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "librust_available_exclude", true, rlibVendorVariant) // Verify the content of the vendor snapshot. @@ -237,16 +327,24 @@ func TestVendorSnapshotExclude(t *testing.T) { sharedVariant := fmt.Sprintf("android_vendor.29_%s_%s_shared", archType, archVariant) sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") + rlibVariant := fmt.Sprintf("android_vendor.29_%s_%s_rlib_rlib-std", archType, archVariant) + rlibDir := filepath.Join(snapshotVariantPath, archDir, "rlib") // Included modules cc.CheckSnapshot(t, ctx, snapshotSingleton, "libinclude", "libinclude.so", sharedDir, sharedVariant) includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libinclude.so.json")) + cc.CheckSnapshot(t, ctx, snapshotSingleton, "librust_include", "librust_include.rlib", rlibDir, rlibVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librust_include.rlib.json")) // Excluded modules cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libexclude", "libexclude.so", sharedDir, sharedVariant) excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libexclude.so.json")) cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude", "libavailable_exclude.so", sharedDir, sharedVariant) excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libavailable_exclude.so.json")) + cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "librust_exclude", "librust_exclude.rlib", rlibDir, rlibVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "librust_exclude.rlib.json")) + cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "librust_available_exclude", "librust_available_exclude.rlib", rlibDir, rlibVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "librust_available_exclude.rlib.json")) } // Verify that each json file for an included module has a rule. @@ -263,3 +361,655 @@ func TestVendorSnapshotExclude(t *testing.T) { } } } + +func TestVendorSnapshotUse(t *testing.T) { + frameworkBp := ` + cc_library { + name: "libvndk", + vendor_available: true, + product_available: true, + vndk: { + enabled: true, + }, + nocrt: true, + } + + cc_library { + name: "libvendor", + vendor: true, + nocrt: true, + no_libcrt: true, + stl: "none", + system_shared_libs: [], + } + + cc_library { + name: "libvendor_available", + vendor_available: true, + nocrt: true, + 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", + } + + rust_binary { + name: "bin", + vendor: true, + srcs: ["bin.rs"], + } + + rust_binary { + name: "bin32", + vendor: true, + compile_multilib: "32", + srcs: ["bin.rs"], + } +` + + vndkBp := ` + vndk_prebuilt_shared { + name: "libvndk", + version: "30", + target_arch: "arm64", + vendor_available: true, + product_available: true, + vndk: { + enabled: true, + }, + arch: { + arm64: { + 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: "26", + target_arch: "arm64", + vendor_available: true, + product_available: true, + vndk: { + enabled: true, + }, + arch: { + arm64: { + 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"], + }, + }, + } +` + + vendorProprietaryBp := ` + cc_library { + name: "libvendor_without_snapshot", + vendor: true, + nocrt: true, + no_libcrt: true, + stl: "none", + system_shared_libs: [], + } + + rust_library { + name: "librust_vendor_available", + crate_name: "rust_vendor", + vendor_available: true, + srcs: ["client.rs"], + } + + rust_ffi_shared { + name: "libclient", + crate_name: "client", + vendor: true, + shared_libs: ["libvndk", "libvendor_available"], + static_libs: ["libvendor", "libvendor_without_snapshot"], + rustlibs: ["librust_vendor_available"], + arch: { + arm64: { + shared_libs: ["lib64"], + }, + arm: { + shared_libs: ["lib32"], + }, + }, + srcs: ["client.rs"], + } + + rust_library_rlib { + name: "libclient_rust", + crate_name: "client_rust", + vendor: true, + shared_libs: ["libvndk", "libvendor_available"], + static_libs: ["libvendor", "libvendor_without_snapshot"], + rustlibs: ["librust_vendor_available"], + arch: { + arm64: { + shared_libs: ["lib64"], + }, + arm: { + shared_libs: ["lib32"], + }, + }, + srcs: ["client.rs"], + } + + rust_binary { + name: "bin_without_snapshot", + vendor: true, + static_libs: ["libvndk"], + srcs: ["bin.rs"], + rustlibs: ["librust_vendor_available"], + } + + vendor_snapshot { + name: "vendor_snapshot", + version: "30", + arch: { + arm64: { + vndk_libs: [ + "libvndk", + ], + static_libs: [ + "libvendor", + "libvndk", + "libclang_rt.builtins-aarch64-android", + ], + shared_libs: [ + "libvendor_available", + "lib64", + ], + rlibs: [ + "libstd", + "libtest", + "librust_vendor_available", + ], + binaries: [ + "bin", + ], + objects: [ + "crtend_so", + "crtbegin_so", + "crtbegin_dynamic", + "crtend_android" + ], + }, + arm: { + vndk_libs: [ + "libvndk", + ], + static_libs: [ + "libvendor", + "libvndk", + "libclang_rt.builtins-arm-android", + ], + shared_libs: [ + "libvendor_available", + "lib32", + ], + rlibs: [ + "libstd", + "libtest", + "librust_vendor_available", + ], + binaries: [ + "bin32", + ], + objects: [ + "crtend_so", + "crtbegin_so", + "crtbegin_dynamic", + "crtend_android" + ], + + }, + } + } + + vendor_snapshot_object { + name: "crtend_so", + version: "30", + target_arch: "arm64", + vendor: true, + stl: "none", + crt: true, + arch: { + arm64: { + src: "crtend_so.o", + }, + arm: { + src: "crtend_so.o", + }, + }, + } + + vendor_snapshot_object { + name: "crtbegin_so", + version: "30", + target_arch: "arm64", + vendor: true, + stl: "none", + crt: true, + arch: { + arm64: { + src: "crtbegin_so.o", + }, + arm: { + src: "crtbegin_so.o", + }, + }, + } + + vendor_snapshot_rlib { + name: "libstd", + version: "30", + target_arch: "arm64", + vendor: true, + sysroot: true, + arch: { + arm64: { + src: "libstd.rlib", + }, + arm: { + src: "libstd.rlib", + }, + }, + } + + vendor_snapshot_rlib { + name: "libtest", + version: "30", + target_arch: "arm64", + vendor: true, + sysroot: true, + arch: { + arm64: { + src: "libtest.rlib", + }, + arm: { + src: "libtest.rlib", + }, + }, + } + + vendor_snapshot_rlib { + name: "librust_vendor_available", + version: "30", + target_arch: "arm64", + vendor: true, + arch: { + arm64: { + src: "librust_vendor_available.rlib", + }, + arm: { + src: "librust_vendor_available.rlib", + }, + }, + } + + vendor_snapshot_object { + name: "crtend_android", + version: "30", + target_arch: "arm64", + vendor: true, + stl: "none", + crt: true, + arch: { + arm64: { + src: "crtend_so.o", + }, + arm: { + src: "crtend_so.o", + }, + }, + } + + vendor_snapshot_object { + name: "crtbegin_dynamic", + version: "30", + target_arch: "arm64", + vendor: true, + stl: "none", + crt: true, + arch: { + arm64: { + src: "crtbegin_so.o", + }, + arm: { + src: "crtbegin_so.o", + }, + }, + } + + vendor_snapshot_static { + name: "libvndk", + version: "30", + target_arch: "arm64", + compile_multilib: "both", + vendor: true, + arch: { + arm64: { + src: "libvndk.a", + }, + arm: { + src: "libvndk.a", + }, + }, + shared_libs: ["libvndk"], + export_shared_lib_headers: ["libvndk"], + } + + vendor_snapshot_static { + name: "libclang_rt.builtins-aarch64-android", + version: "30", + target_arch: "arm64", + vendor: true, + arch: { + arm64: { + src: "libclang_rt.builtins-aarch64-android.a", + }, + }, + } + + vendor_snapshot_static { + name: "libclang_rt.builtins-arm-android", + version: "30", + target_arch: "arm64", + vendor: true, + arch: { + arm: { + src: "libclang_rt.builtins-arm-android.a", + }, + }, + } + + vendor_snapshot_shared { + name: "lib32", + version: "30", + target_arch: "arm64", + compile_multilib: "32", + vendor: true, + arch: { + arm: { + src: "lib32.so", + }, + }, + } + + vendor_snapshot_shared { + name: "lib64", + version: "30", + target_arch: "arm64", + compile_multilib: "64", + vendor: true, + arch: { + arm64: { + src: "lib64.so", + }, + }, + } + vendor_snapshot_shared { + name: "liblog", + version: "30", + target_arch: "arm64", + compile_multilib: "64", + vendor: true, + arch: { + arm64: { + src: "liblog.so", + }, + }, + } + + vendor_snapshot_static { + name: "libvendor", + version: "30", + target_arch: "arm64", + compile_multilib: "both", + vendor: true, + arch: { + arm64: { + src: "libvendor.a", + export_include_dirs: ["include/libvendor"], + }, + arm: { + src: "libvendor.a", + export_include_dirs: ["include/libvendor"], + }, + }, + } + + vendor_snapshot_shared { + name: "libvendor_available", + 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_binary { + name: "bin", + version: "30", + target_arch: "arm64", + compile_multilib: "64", + vendor: true, + arch: { + arm64: { + src: "bin", + }, + }, + } + + 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: "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: { + src: "bin", + }, + }, + } +` + + mockFS := android.MockFS{ + "framework/Android.bp": []byte(frameworkBp), + "framework/bin.rs": nil, + "vendor/Android.bp": []byte(vendorProprietaryBp), + "vendor/bin": nil, + "vendor/bin32": nil, + "vendor/bin.rs": nil, + "vendor/client.rs": 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, + "vendor/lib32.so": nil, + "vendor/lib64.so": nil, + "vendor/liblog.so": nil, + "vendor/libstd.rlib": nil, + "vendor/libtest.rlib": nil, + "vendor/librust_vendor_available.rlib": nil, + "vendor/crtbegin_so.o": nil, + "vendor/crtend_so.o": nil, + "vendor/libclang_rt.builtins-aarch64-android.a": nil, + "vendor/libclang_rt.builtins-arm-android.a": nil, + "vndk/Android.bp": []byte(vndkBp), + "vndk/include/libvndk/a.h": nil, + "vndk/libvndk.so": nil, + } + + sharedVariant := "android_vendor.30_arm64_armv8-a_shared" + rlibVariant := "android_vendor.30_arm64_armv8-a_rlib_rlib-std" + staticVariant := "android_vendor.30_arm64_armv8-a_static" + binaryVariant := "android_vendor.30_arm64_armv8-a" + + shared32Variant := "android_vendor.30_arm_armv7-a-neon_shared" + binary32Variant := "android_vendor.30_arm_armv7-a-neon" + + ctx := testRustVndkFsVersions(t, "", mockFS, "30", "current", "31") + + // libclient uses libvndk.vndk.30.arm64, libvendor.vendor_static.30.arm64, libvendor_without_snapshot + libclientLdFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("rustc").Args["linkFlags"] + for _, input := range [][]string{ + []string{sharedVariant, "libvndk.vndk.30.arm64"}, + []string{staticVariant, "libvendor.vendor_static.30.arm64"}, + []string{staticVariant, "libvendor_without_snapshot"}, + } { + outputPaths := cc.GetOutputPaths(ctx, input[0] /* variant */, []string{input[1]} /* module name */) + if !strings.Contains(libclientLdFlags, outputPaths[0].String()) { + t.Errorf("libflags for libclient must contain %#v, but was %#v", outputPaths[0], libclientLdFlags) + } + } + + libclientAndroidMkSharedLibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).Properties.AndroidMkSharedLibs + if g, w := libclientAndroidMkSharedLibs, []string{"libvndk.vendor", "libvendor_available.vendor", "lib64", "liblog.vendor", "libc.vendor", "libm.vendor", "libdl.vendor"}; !reflect.DeepEqual(g, w) { + t.Errorf("wanted libclient AndroidMkSharedLibs %q, got %q", w, g) + } + + libclientAndroidMkStaticLibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).Properties.AndroidMkStaticLibs + if g, w := libclientAndroidMkStaticLibs, []string{"libvendor", "libvendor_without_snapshot", "libclang_rt.builtins-aarch64-android.vendor"}; !reflect.DeepEqual(g, w) { + t.Errorf("wanted libclient AndroidMkStaticLibs %q, got %q", w, g) + } + + libclientAndroidMkRlibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).Properties.AndroidMkRlibs + if g, w := libclientAndroidMkRlibs, []string{"librust_vendor_available.vendor_rlib.30.arm64.rlib-std", "libstd.vendor_rlib.30.arm64", "libtest.vendor_rlib.30.arm64"}; !reflect.DeepEqual(g, w) { + t.Errorf("wanted libclient libclientAndroidMkRlibs %q, got %q", w, g) + } + + libclientAndroidMkDylibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).Properties.AndroidMkDylibs + if len(libclientAndroidMkDylibs) > 0 { + t.Errorf("wanted libclient libclientAndroidMkDylibs [], got %q", libclientAndroidMkDylibs) + } + + libclient32AndroidMkSharedLibs := ctx.ModuleForTests("libclient", shared32Variant).Module().(*Module).Properties.AndroidMkSharedLibs + if g, w := libclient32AndroidMkSharedLibs, []string{"libvndk.vendor", "libvendor_available.vendor", "lib32", "liblog.vendor", "libc.vendor", "libm.vendor", "libdl.vendor"}; !reflect.DeepEqual(g, w) { + t.Errorf("wanted libclient32 AndroidMkSharedLibs %q, got %q", w, g) + } + + libclientRustAndroidMkRlibs := ctx.ModuleForTests("libclient_rust", rlibVariant).Module().(*Module).Properties.AndroidMkRlibs + if g, w := libclientRustAndroidMkRlibs, []string{"librust_vendor_available.vendor_rlib.30.arm64.rlib-std", "libstd.vendor_rlib.30.arm64", "libtest.vendor_rlib.30.arm64"}; !reflect.DeepEqual(g, w) { + t.Errorf("wanted libclient libclientAndroidMkRlibs %q, got %q", w, g) + } + + binWithoutSnapshotLdFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("rustc").Args["linkFlags"] + libVndkStaticOutputPaths := cc.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) + } + + // 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.30 variant + libvendorVariants := ctx.ModuleVariantsForTests("libvendor") + if android.InList(sharedVariant, libvendorVariants) { + t.Errorf("libvendor must not have variant %#v, but it does", sharedVariant) + } + + libvendorAvailableVariants := ctx.ModuleVariantsForTests("libvendor_available") + if android.InList(sharedVariant, libvendorAvailableVariants) { + t.Errorf("libvendor_available must not have variant %#v, but it does", sharedVariant) + } + + binVariants := ctx.ModuleVariantsForTests("bin") + if android.InList(binaryVariant, binVariants) { + t.Errorf("bin must not have variant %#v, but it does", sharedVariant) + } +}