From 1921e8003dd4e2a622e85ac1653f1fb3a683e569 Mon Sep 17 00:00:00 2001 From: Ivan Lozano Date: Thu, 20 May 2021 13:39:16 -0400 Subject: [PATCH 1/3] Rust cdylib/statliclib support for vendor snapshot. Adds support for platform vendor_available Rust FFI libraries and binaries to be included in the vendor snapshot. Because rlib and dylibs are not yet in snapshots, libstd cannot be included in a vendor snapshot. As a result, vendor-specific Rust code can't be guaranteed to work with the platform-provided vendor_available modules built with a newer toolchain. For now, a check is added indicating vendor-specific Rust code is unsupported. This changes the linkage for vendor variants of these modules to default to rlib linkage since dylibs cannot be included in the snapshot yet. Bug: 184042776 Test: m nothing # new Soong tests pass Change-Id: I502eaa4bb962eb87ff868fcf49b435f0d2f982e6 --- rust/Android.bp | 1 + rust/binary.go | 5 + rust/image.go | 5 + rust/library.go | 76 +++++++++- rust/rust.go | 87 ++++++++++-- rust/rust_test.go | 46 ++++-- rust/snapshot_utils.go | 33 +++-- rust/testing.go | 5 + rust/vendor_snapshot_test.go | 265 +++++++++++++++++++++++++++++++++++ 9 files changed, 487 insertions(+), 36 deletions(-) create mode 100644 rust/vendor_snapshot_test.go diff --git a/rust/Android.bp b/rust/Android.bp index b611672d4..63983904c 100644 --- a/rust/Android.bp +++ b/rust/Android.bp @@ -53,6 +53,7 @@ bootstrap_go_package { "rust_test.go", "source_provider_test.go", "test_test.go", + "vendor_snapshot_test.go", ], pluginFor: ["soong_build"], } diff --git a/rust/binary.go b/rust/binary.go index ffc0413ec..8d0a0a7a0 100644 --- a/rust/binary.go +++ b/rust/binary.go @@ -137,6 +137,9 @@ func (binary *binaryDecorator) autoDep(ctx android.BottomUpMutatorContext) autoD // Binaries default to dylib dependencies for device, rlib for host. if binary.preferRlib() { return rlibAutoDep + } else if mod, ok := ctx.Module().(*Module); ok && mod.InVendor() { + // Vendor Rust binaries should prefer rlibs. + return rlibAutoDep } else if ctx.Device() { return dylibAutoDep } else { @@ -147,6 +150,8 @@ func (binary *binaryDecorator) autoDep(ctx android.BottomUpMutatorContext) autoD func (binary *binaryDecorator) stdLinkage(ctx *depsContext) RustLinkage { if binary.preferRlib() { return RlibLinkage + } else if ctx.RustModule().InVendor() { + return RlibLinkage } return binary.baseCompiler.stdLinkage(ctx) } diff --git a/rust/image.go b/rust/image.go index 900842ec8..6cfb42c7d 100644 --- a/rust/image.go +++ b/rust/image.go @@ -202,6 +202,8 @@ func (mod *Module) SetImageVariation(ctx android.BaseModuleContext, variant stri func (mod *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { // Rust does not support installing to the product image yet. + vendorSpecific := mctx.SocSpecific() || mctx.DeviceSpecific() + if Bool(mod.VendorProperties.Product_available) { mctx.PropertyErrorf("product_available", "Rust modules do not yet support being available to the product image") @@ -217,6 +219,9 @@ func (mod *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { mctx.PropertyErrorf("vendor_ramdisk_available", "cannot be set for rust_ffi or rust_ffi_shared modules.") } } + if vendorSpecific { + mctx.PropertyErrorf("vendor", "Vendor-only non-rust_ffi Rust modules are not supported.") + } cc.MutateImage(mctx, mod) diff --git a/rust/library.go b/rust/library.go index 1bdf83a43..7421817cc 100644 --- a/rust/library.go +++ b/rust/library.go @@ -99,6 +99,8 @@ type libraryDecorator struct { MutatedProperties LibraryMutatedProperties includeDirs android.Paths sourceProvider SourceProvider + + collectedSnapshotHeaders android.Paths } type libraryInterface interface { @@ -220,7 +222,10 @@ func (library *libraryDecorator) setSource() { } func (library *libraryDecorator) autoDep(ctx android.BottomUpMutatorContext) autoDep { - if library.preferRlib() { + if ctx.Module().(*Module).InVendor() { + // Vendor modules should statically link libstd. + return rlibAutoDep + } else if library.preferRlib() { return rlibAutoDep } else if library.rlib() || library.static() { return rlibAutoDep @@ -236,7 +241,10 @@ func (library *libraryDecorator) autoDep(ctx android.BottomUpMutatorContext) aut } func (library *libraryDecorator) stdLinkage(ctx *depsContext) RustLinkage { - if library.static() || library.MutatedProperties.VariantIsStaticStd { + if ctx.RustModule().InVendor() { + // Vendor modules should statically link libstd. + return RlibLinkage + } else if library.static() || library.MutatedProperties.VariantIsStaticStd { return RlibLinkage } else if library.baseCompiler.preferRlib() { return RlibLinkage @@ -623,6 +631,19 @@ func LibraryMutator(mctx android.BottomUpMutatorContext) { // Disable dylib Vendor Ramdisk variations until we support these. v.(*Module).Disable() } + + variation := v.(*Module).ModuleBase.ImageVariation().Variation + if strings.HasPrefix(variation, cc.VendorVariationPrefix) && + m.HasVendorVariant() && + !cc.IsVendorProprietaryModule(mctx) && + strings.TrimPrefix(variation, cc.VendorVariationPrefix) == mctx.DeviceConfig().VndkVersion() { + + // cc.MutateImage runs before LibraryMutator, so vendor variations which are meant for rlibs only are + // produced for Dylibs; however, dylibs should not be enabled for boardVndkVersion for + // non-vendor proprietary modules. + v.(*Module).Disable() + } + case "source": v.(*Module).compiler.(libraryInterface).setSource() // The source variant does not produce any library. @@ -671,3 +692,54 @@ func LibstdMutator(mctx android.BottomUpMutatorContext) { } } } + +func (l *libraryDecorator) snapshotHeaders() android.Paths { + if l.collectedSnapshotHeaders == nil { + panic("snapshotHeaders() must be called after collectHeadersForSnapshot()") + } + return l.collectedSnapshotHeaders +} + +// collectHeadersForSnapshot collects all exported headers from library. +// It globs header files in the source tree for exported include directories, +// and tracks generated header files separately. +// +// This is to be called from GenerateAndroidBuildActions, and then collected +// header files can be retrieved by snapshotHeaders(). +func (l *libraryDecorator) collectHeadersForSnapshot(ctx android.ModuleContext, deps PathDeps) { + ret := android.Paths{} + + // Glob together the headers from the modules include_dirs property + for _, path := range android.CopyOfPaths(l.includeDirs) { + dir := path.String() + glob, err := ctx.GlobWithDeps(dir+"/**/*", nil) + if err != nil { + ctx.ModuleErrorf("glob failed: %#v", err) + return + } + + for _, header := range glob { + // Filter out only the files with extensions that are headers. + found := false + for _, ext := range cc.HeaderExts { + if strings.HasSuffix(header, ext) { + found = true + break + } + } + if !found { + continue + } + ret = append(ret, android.PathForSource(ctx, header)) + } + } + + // Glob together the headers from C dependencies as well, starting with non-generated headers. + ret = append(ret, cc.GlobHeadersForSnapshot(ctx, append(android.CopyOfPaths(deps.depIncludePaths), deps.depSystemIncludePaths...))...) + + // Collect generated headers from C dependencies. + ret = append(ret, cc.GlobGeneratedHeadersForSnapshot(ctx, deps.depGeneratedHeaders)...) + + // TODO(185577950): If support for generated headers is added, they need to be collected here as well. + l.collectedSnapshotHeaders = ret +} diff --git a/rust/rust.go b/rust/rust.go index 46c8f250c..7a8687c8b 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -85,6 +85,9 @@ type BaseProperties struct { VendorRamdiskVariantNeeded bool `blueprint:"mutated"` ExtraVariants []string `blueprint:"mutated"` + // Used by vendor snapshot to record dependencies from snapshot modules. + SnapshotSharedLibs []string `blueprint:"mutated"` + // Make this module available when building for vendor ramdisk. // On device without a dedicated recovery partition, the module is only // available after switching root into @@ -92,6 +95,20 @@ type BaseProperties struct { // the recovery variant instead (TODO(b/165791368) recovery not yet supported) Vendor_ramdisk_available *bool + // Normally Soong uses the directory structure to decide which modules + // should be included (framework) or excluded (non-framework) from the + // different snapshots (vendor, recovery, etc.), but this property + // allows a partner to exclude a module normally thought of as a + // framework module from the vendor snapshot. + Exclude_from_vendor_snapshot *bool + + // Normally Soong uses the directory structure to decide which modules + // should be included (framework) or excluded (non-framework) from the + // different snapshots (vendor, recovery, etc.), but this property + // allows a partner to exclude a module normally thought of as a + // framework module from the recovery snapshot. + Exclude_from_recovery_snapshot *bool + // Minimum sdk version that the artifact should support when it runs as part of mainline modules(APEX). Min_sdk_version *string @@ -826,6 +843,14 @@ func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { mod.docTimestampFile = mod.compiler.rustdoc(ctx, flags, deps) + // glob exported headers for snapshot, if BOARD_VNDK_VERSION is current or + // RECOVERY_SNAPSHOT_VERSION is current. + if lib, ok := mod.compiler.(snapshotLibraryInterface); ok { + if cc.ShouldCollectHeadersForSnapshot(ctx, mod, apexInfo) { + lib.collectHeadersForSnapshot(ctx, deps) + } + } + apexInfo := actx.Provider(android.ApexInfoProvider).(android.ApexInfo) if mod.installable(apexInfo) { mod.compiler.install(ctx) @@ -1056,6 +1081,10 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { depPaths.depClangFlags = append(depPaths.depClangFlags, exportedInfo.Flags...) depPaths.depGeneratedHeaders = append(depPaths.depGeneratedHeaders, exportedInfo.GeneratedHeaders...) directSharedLibDeps = append(directSharedLibDeps, ccDep) + + // Record baseLibName for snapshots. + mod.Properties.SnapshotSharedLibs = append(mod.Properties.SnapshotSharedLibs, cc.BaseLibName(depName)) + mod.Properties.AndroidMkSharedLibs = append(mod.Properties.AndroidMkSharedLibs, makeLibName) exportDep = true case cc.IsHeaderDepTag(depTag): @@ -1161,6 +1190,11 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) { deps := mod.deps(ctx) var commonDepVariations []blueprint.Variation + var snapshotInfo *cc.SnapshotInfo + + if ctx.Os() == android.Android { + deps.SharedLibs, _ = cc.RewriteLibs(mod, &snapshotInfo, actx, ctx.Config(), deps.SharedLibs) + } stdLinkage := "dylib-std" if mod.compiler.stdLinkage(ctx) == RlibLinkage { @@ -1168,20 +1202,25 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) { } rlibDepVariations := commonDepVariations + if lib, ok := mod.compiler.(libraryInterface); !ok || !lib.sysroot() { rlibDepVariations = append(rlibDepVariations, blueprint.Variation{Mutator: "rust_stdlinkage", Variation: stdLinkage}) } + // rlibs actx.AddVariationDependencies( append(rlibDepVariations, []blueprint.Variation{ {Mutator: "rust_libraries", Variation: rlibVariation}}...), rlibDepTag, deps.Rlibs...) + + // dylibs actx.AddVariationDependencies( append(commonDepVariations, []blueprint.Variation{ {Mutator: "rust_libraries", Variation: dylibVariation}}...), dylibDepTag, deps.Dylibs...) + // rustlibs if deps.Rustlibs != nil && !mod.compiler.Disabled() { autoDep := mod.compiler.(autoDeppable).autoDep(ctx) if autoDep.depTag == rlibDepTag { @@ -1194,10 +1233,12 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) { autoDep.depTag, deps.Rustlibs...) } } + + // stdlibs if deps.Stdlibs != nil { if mod.compiler.stdLinkage(ctx) == RlibLinkage { actx.AddVariationDependencies( - append(commonDepVariations, blueprint.Variation{Mutator: "rust_libraries", Variation: "rlib"}), + append(commonDepVariations, []blueprint.Variation{{Mutator: "rust_libraries", Variation: "rlib"}}...), rlibDepTag, deps.Stdlibs...) } else { actx.AddVariationDependencies( @@ -1205,24 +1246,45 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) { dylibDepTag, deps.Stdlibs...) } } - actx.AddVariationDependencies(append(commonDepVariations, - blueprint.Variation{Mutator: "link", Variation: "shared"}), - cc.SharedDepTag(), deps.SharedLibs...) - actx.AddVariationDependencies(append(commonDepVariations, - blueprint.Variation{Mutator: "link", Variation: "static"}), - cc.StaticDepTag(false), deps.StaticLibs...) - actx.AddVariationDependencies(append(commonDepVariations, - blueprint.Variation{Mutator: "link", Variation: "static"}), - cc.StaticDepTag(true), deps.WholeStaticLibs...) + + for _, lib := range deps.SharedLibs { + depTag := cc.SharedDepTag() + name, version := cc.StubsLibNameAndVersion(lib) + + variations := []blueprint.Variation{ + {Mutator: "link", Variation: "shared"}, + } + cc.AddSharedLibDependenciesWithVersions(ctx, mod, variations, depTag, name, version, false) + } + + for _, lib := range deps.WholeStaticLibs { + depTag := cc.StaticDepTag(true) + lib = cc.RewriteSnapshotLib(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).StaticLibs) + + actx.AddVariationDependencies([]blueprint.Variation{ + {Mutator: "link", Variation: "static"}, + }, depTag, lib) + } + + for _, lib := range deps.StaticLibs { + depTag := cc.StaticDepTag(false) + lib = cc.RewriteSnapshotLib(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).StaticLibs) + + actx.AddVariationDependencies([]blueprint.Variation{ + {Mutator: "link", Variation: "static"}, + }, depTag, lib) + } actx.AddVariationDependencies(nil, cc.HeaderDepTag(), deps.HeaderLibs...) crtVariations := cc.GetCrtVariations(ctx, mod) if deps.CrtBegin != "" { - actx.AddVariationDependencies(crtVariations, cc.CrtBeginDepTag, deps.CrtBegin) + actx.AddVariationDependencies(crtVariations, cc.CrtBeginDepTag, + cc.RewriteSnapshotLib(deps.CrtBegin, cc.GetSnapshot(mod, &snapshotInfo, actx).Objects)) } if deps.CrtEnd != "" { - actx.AddVariationDependencies(crtVariations, cc.CrtEndDepTag, deps.CrtEnd) + actx.AddVariationDependencies(crtVariations, cc.CrtEndDepTag, + cc.RewriteSnapshotLib(deps.CrtEnd, cc.GetSnapshot(mod, &snapshotInfo, actx).Objects)) } if mod.sourceProvider != nil { @@ -1232,6 +1294,7 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) { bindgen.Properties.Custom_bindgen) } } + // proc_macros are compiler plugins, and so we need the host arch variant as a dependendcy. actx.AddFarVariationDependencies(ctx.Config().BuildOSTarget.Variations(), procMacroDepTag, deps.ProcMacros...) } diff --git a/rust/rust_test.go b/rust/rust_test.go index 6ae05d988..f07f86bf8 100644 --- a/rust/rust_test.go +++ b/rust/rust_test.go @@ -37,21 +37,28 @@ var prepareForRustTest = android.GroupFixturePreparers( genrule.PrepareForTestWithGenRuleBuildComponents, - PrepareForIntegrationTestWithRust, + PrepareForTestWithRustIncludeVndk, + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.DeviceVndkVersion = StringPtr("current") + variables.ProductVndkVersion = StringPtr("current") + variables.Platform_vndk_version = StringPtr("29") + }), ) var rustMockedFiles = android.MockFS{ - "foo.rs": nil, - "foo.c": nil, - "src/bar.rs": nil, - "src/any.h": nil, - "proto.proto": nil, - "proto/buf.proto": nil, - "buf.proto": nil, - "foo.proto": nil, - "liby.so": nil, - "libz.so": nil, - "data.txt": nil, + "foo.rs": nil, + "foo.c": nil, + "src/bar.rs": nil, + "src/any.h": nil, + "c_includes/c_header.h": nil, + "rust_includes/rust_headers.h": nil, + "proto.proto": nil, + "proto/buf.proto": nil, + "buf.proto": nil, + "foo.proto": nil, + "liby.so": nil, + "libz.so": nil, + "data.txt": nil, } // testRust returns a TestContext in which a basic environment has been setup. @@ -67,10 +74,16 @@ func testRust(t *testing.T, bp string) *android.TestContext { } func testRustVndk(t *testing.T, bp string) *android.TestContext { + return testRustVndkFs(t, bp, rustMockedFiles) +} + +const vendorVariant = "android_vendor.29_arm64_armv8-a_shared" + +func testRustVndkFs(t *testing.T, bp string, fs android.MockFS) *android.TestContext { skipTestIfOsNotSupported(t) result := android.GroupFixturePreparers( prepareForRustTest, - rustMockedFiles.AddToFixture(), + fs.AddToFixture(), android.FixtureModifyProductVariables( func(variables android.FixtureProductVariables) { variables.DeviceVndkVersion = StringPtr("current") @@ -80,6 +93,7 @@ func testRustVndk(t *testing.T, bp string) *android.TestContext { ), ).RunTestWithBp(t, bp) return result.TestContext + } // testRustCov returns a TestContext in which a basic environment has been @@ -115,10 +129,14 @@ func testRustError(t *testing.T, pattern string, bp string) { // testRustVndkError is similar to testRustError, but can be used to test VNDK-related errors. func testRustVndkError(t *testing.T, pattern string, bp string) { + testRustVndkFsError(t, pattern, bp, rustMockedFiles) +} + +func testRustVndkFsError(t *testing.T, pattern string, bp string, fs android.MockFS) { skipTestIfOsNotSupported(t) android.GroupFixturePreparers( prepareForRustTest, - rustMockedFiles.AddToFixture(), + fs.AddToFixture(), android.FixtureModifyProductVariables( func(variables android.FixtureProductVariables) { variables.DeviceVndkVersion = StringPtr("current") diff --git a/rust/snapshot_utils.go b/rust/snapshot_utils.go index 943c79098..9d5154ce2 100644 --- a/rust/snapshot_utils.go +++ b/rust/snapshot_utils.go @@ -18,18 +18,34 @@ import ( "android/soong/android" ) +// snapshotLibraryInterface is an interface for libraries captured to VNDK / vendor snapshots. +type snapshotLibraryInterface interface { + libraryInterface + + // collectHeadersForSnapshot is called in GenerateAndroidBuildActions for snapshot aware + // modules (See isSnapshotAware below). + // This function should gather all headers needed for snapshot. + collectHeadersForSnapshot(ctx android.ModuleContext, deps PathDeps) + + // snapshotHeaders should return collected headers by collectHeadersForSnapshot. + // Calling snapshotHeaders before collectHeadersForSnapshot is an error. + snapshotHeaders() android.Paths +} + func (mod *Module) ExcludeFromVendorSnapshot() bool { - // TODO Rust does not yet support snapshotting - return false + return Bool(mod.Properties.Exclude_from_vendor_snapshot) } func (mod *Module) ExcludeFromRecoverySnapshot() bool { - // TODO Rust does not yet support snapshotting - return false + return Bool(mod.Properties.Exclude_from_recovery_snapshot) } func (mod *Module) IsSnapshotLibrary() bool { - // TODO Rust does not yet support snapshotting + 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() + } return false } @@ -39,8 +55,7 @@ func (mod *Module) SnapshotRuntimeLibs() []string { } func (mod *Module) SnapshotSharedLibs() []string { - // TODO Rust does not yet support snapshotting - return []string{} + return mod.Properties.SnapshotSharedLibs } func (mod *Module) Symlinks() []string { @@ -49,6 +64,8 @@ func (mod *Module) Symlinks() []string { } func (m *Module) SnapshotHeaders() android.Paths { - // TODO Rust does not yet support snapshotting + if l, ok := m.compiler.(snapshotLibraryInterface); ok { + return l.snapshotHeaders() + } return android.Paths{} } diff --git a/rust/testing.go b/rust/testing.go index a0f86b220..a7cbf54d8 100644 --- a/rust/testing.go +++ b/rust/testing.go @@ -45,6 +45,11 @@ var PrepareForIntegrationTestWithRust = android.GroupFixturePreparers( PrepareForTestWithRustDefaultModules, ) +var PrepareForTestWithRustIncludeVndk = android.GroupFixturePreparers( + PrepareForIntegrationTestWithRust, + cc.PrepareForTestWithCcIncludeVndk, +) + func GatherRequiredDepsForTest() string { bp := ` rust_prebuilt_library { diff --git a/rust/vendor_snapshot_test.go b/rust/vendor_snapshot_test.go new file mode 100644 index 000000000..c5183f754 --- /dev/null +++ b/rust/vendor_snapshot_test.go @@ -0,0 +1,265 @@ +// 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 ( + "fmt" + "path/filepath" + "strings" + "testing" + + "android/soong/android" + "android/soong/cc" +) + +func TestVendorSnapshotCapture(t *testing.T) { + bp := ` + rust_ffi { + name: "librustvendor_available", + crate_name: "rustvendor_available", + srcs: ["lib.rs"], + vendor_available: true, + include_dirs: ["rust_headers/"], + } + + rust_binary { + name: "vendor_available_bin", + vendor_available: true, + srcs: ["srcs/lib.rs"], + } + +` + skipTestIfOsNotSupported(t) + result := android.GroupFixturePreparers( + prepareForRustTest, + rustMockedFiles.AddToFixture(), + android.FixtureModifyProductVariables( + func(variables android.FixtureProductVariables) { + variables.DeviceVndkVersion = StringPtr("current") + variables.Platform_vndk_version = StringPtr("29") + }, + ), + ).RunTestWithBp(t, bp) + ctx := result.TestContext + + // Check Vendor snapshot output. + + snapshotDir := "vendor-snapshot" + snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64") + snapshotSingleton := ctx.SingletonForTests("vendor-snapshot") + var jsonFiles []string + for _, arch := range [][]string{ + []string{"arm64", "armv8-a"}, + []string{"arm", "armv7-a-neon"}, + } { + archType := arch[0] + archVariant := arch[1] + archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant) + + // 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) + jsonFiles = append(jsonFiles, + filepath.Join(sharedDir, "librustvendor_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) + jsonFiles = append(jsonFiles, + filepath.Join(staticDir, "librustvendor_available.a.json")) + + // For binary executables, all 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) + jsonFiles = append(jsonFiles, + filepath.Join(binaryDir, "vendor_available_bin.json")) + } + } + + for _, jsonFile := range jsonFiles { + // verify all json files exist + if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil { + t.Errorf("%q expected but not found; #%v", jsonFile, jsonFiles) + } + } + + // fake snapshot should have all outputs in the normal snapshot. + fakeSnapshotSingleton := ctx.SingletonForTests("vendor-fake-snapshot") + + for _, output := range snapshotSingleton.AllOutputs() { + fakeOutput := strings.Replace(output, "/vendor-snapshot/", "/fake/vendor-snapshot/", 1) + if fakeSnapshotSingleton.MaybeOutput(fakeOutput).Rule == nil { + t.Errorf("%q expected but not found", fakeOutput) + } + } +} + +func TestVendorSnapshotDirected(t *testing.T) { + bp := ` + rust_ffi_shared { + name: "librustvendor_available", + crate_name: "rustvendor_available", + srcs: ["lib.rs"], + vendor_available: true, + } + + rust_ffi_shared { + name: "librustvendor_exclude", + crate_name: "rustvendor_exclude", + srcs: ["lib.rs"], + vendor_available: true, + } +` + ctx := testRustVndk(t, bp) + ctx.Config().TestProductVariables.VendorSnapshotModules = make(map[string]bool) + ctx.Config().TestProductVariables.VendorSnapshotModules["librustvendor_available"] = true + ctx.Config().TestProductVariables.DirectedVendorSnapshot = true + + // Check Vendor snapshot output. + + snapshotDir := "vendor-snapshot" + snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64") + snapshotSingleton := ctx.SingletonForTests("vendor-snapshot") + + var includeJsonFiles []string + + for _, arch := range [][]string{ + []string{"arm64", "armv8-a"}, + []string{"arm", "armv7-a-neon"}, + } { + archType := arch[0] + archVariant := arch[1] + archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant) + + sharedVariant := fmt.Sprintf("android_vendor.29_%s_%s_shared", archType, archVariant) + sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") + + // Included modules + cc.CheckSnapshot(t, ctx, snapshotSingleton, "librustvendor_available", "librustvendor_available.so", sharedDir, sharedVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "librustvendor_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")) + } + + // Verify that each json file for an included module has a rule. + for _, jsonFile := range includeJsonFiles { + if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil { + t.Errorf("include json file %q not found", jsonFile) + } + } +} + +func TestVendorSnapshotExclude(t *testing.T) { + + // This test verifies that the exclude_from_vendor_snapshot property + // makes its way from the Android.bp source file into the module data + // structure. It also verifies that modules are correctly included or + // 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", + crate_name: "include", + srcs: ["include.rs"], + vendor_available: true, + } + + rust_ffi_shared { + name: "libexclude", + crate_name: "exclude", + srcs: ["exclude.rs"], + vendor_available: true, + exclude_from_vendor_snapshot: true, + } + + rust_ffi_shared { + name: "libavailable_exclude", + crate_name: "available_exclude", + srcs: ["lib.rs"], + vendor_available: true, + exclude_from_vendor_snapshot: true, + } + ` + + mockFS := map[string][]byte{ + "framework/Android.bp": []byte(frameworkBp), + "framework/include.rs": nil, + "framework/exclude.rs": nil, + } + + 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) + + // Verify the content of the vendor snapshot. + + snapshotDir := "vendor-snapshot" + snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64") + snapshotSingleton := ctx.SingletonForTests("vendor-snapshot") + + var includeJsonFiles []string + var excludeJsonFiles []string + + for _, arch := range [][]string{ + []string{"arm64", "armv8-a"}, + []string{"arm", "armv7-a-neon"}, + } { + archType := arch[0] + archVariant := arch[1] + archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant) + + sharedVariant := fmt.Sprintf("android_vendor.29_%s_%s_shared", archType, archVariant) + sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") + + // Included modules + cc.CheckSnapshot(t, ctx, snapshotSingleton, "libinclude", "libinclude.so", sharedDir, sharedVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libinclude.so.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")) + } + + // Verify that each json file for an included module has a rule. + for _, jsonFile := range includeJsonFiles { + if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil { + t.Errorf("include json file %q not found", jsonFile) + } + } + + // Verify that each json file for an excluded module has no rule. + for _, jsonFile := range excludeJsonFiles { + if snapshotSingleton.MaybeOutput(jsonFile).Rule != nil { + t.Errorf("exclude json file %q found", jsonFile) + } + } +} From d1dec54988630cabaf15b2353e55460f79c05b0c Mon Sep 17 00:00:00 2001 From: Ivan Lozano Date: Wed, 26 May 2021 15:33:11 -0400 Subject: [PATCH 2/3] Export cc functions for snapshotting Rust rlibs. Export additional fuctions, structs, and interfaces from cc for use in the rust package to allow for rlib snapshotting. Bug: 184042776 Test: m nothing Change-Id: I4c53b9378d5d5b5973dbd23ab692cdfb2ede60b9 --- cc/cc.go | 8 +-- cc/image.go | 4 +- cc/snapshot_prebuilt.go | 144 ++++++++++++++++++++-------------------- cc/snapshot_utils.go | 2 +- cc/vendor_snapshot.go | 4 +- cc/vndk.go | 2 +- cc/vndk_prebuilt.go | 14 ++-- 7 files changed, 89 insertions(+), 89 deletions(-) diff --git a/cc/cc.go b/cc/cc.go index 2ee851ba7..fa464efe2 100644 --- a/cc/cc.go +++ b/cc/cc.go @@ -1267,8 +1267,8 @@ func (c *Module) nativeCoverage() bool { } func (c *Module) IsSnapshotPrebuilt() bool { - if p, ok := c.linker.(snapshotInterface); ok { - return p.isSnapshotPrebuilt() + if p, ok := c.linker.(SnapshotInterface); ok { + return p.IsSnapshotPrebuilt() } return false } @@ -2946,10 +2946,10 @@ func MakeLibName(ctx android.ModuleContext, c LinkableInterface, ccDep LinkableI 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 { + if snapshotPrebuilt, ok := ccDepModule.linker.(SnapshotInterface); ok { baseName := ccDepModule.BaseModuleName() - return baseName + snapshotPrebuilt.snapshotAndroidMkSuffix() + return baseName + snapshotPrebuilt.SnapshotAndroidMkSuffix() } } diff --git a/cc/image.go b/cc/image.go index 9370c40bf..c9c0e63a6 100644 --- a/cc/image.go +++ b/cc/image.go @@ -365,8 +365,8 @@ func (m *Module) SetCoreVariantNeeded(b bool) { } func (m *Module) SnapshotVersion(mctx android.BaseModuleContext) string { - if snapshot, ok := m.linker.(snapshotInterface); ok { - return snapshot.version() + 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? diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go index 48b7c6952..8ab0134b2 100644 --- a/cc/snapshot_prebuilt.go +++ b/cc/snapshot_prebuilt.go @@ -28,7 +28,7 @@ import ( // Defines the specifics of different images to which the snapshot process is applicable, e.g., // vendor, recovery, ramdisk. -type snapshotImage interface { +type SnapshotImage interface { // Returns true if a snapshot should be generated for this image. shouldGenerateSnapshot(ctx android.SingletonContext) bool @@ -264,8 +264,8 @@ func init() { const ( snapshotHeaderSuffix = "_header." - snapshotSharedSuffix = "_shared." - snapshotStaticSuffix = "_static." + SnapshotSharedSuffix = "_shared." + SnapshotStaticSuffix = "_static." snapshotBinarySuffix = "_binary." snapshotObjectSuffix = "_object." ) @@ -284,14 +284,14 @@ type snapshot struct { properties SnapshotProperties - baseSnapshot baseSnapshotDecorator + baseSnapshot BaseSnapshotDecorator - image snapshotImage + image SnapshotImage } func (s *snapshot) ImageMutatorBegin(ctx android.BaseModuleContext) { cfg := ctx.DeviceConfig() - if !s.image.isUsingSnapshot(cfg) || s.image.targetSnapshotVersion(cfg) != s.baseSnapshot.version() { + if !s.image.isUsingSnapshot(cfg) || s.image.targetSnapshotVersion(cfg) != s.baseSnapshot.Version() { s.Disable() } } @@ -341,7 +341,7 @@ func (s *snapshot) DepsMutator(ctx android.BottomUpMutatorContext) { for _, name := range names { snapshotMap[name] = name + getSnapshotNameSuffix(snapshotSuffix+moduleSuffix, - s.baseSnapshot.version(), + s.baseSnapshot.Version(), ctx.DeviceConfig().Arches()[0].ArchType.String()) } return snapshotMap @@ -351,8 +351,8 @@ func (s *snapshot) DepsMutator(ctx android.BottomUpMutatorContext) { headers := collectSnapshotMap(s.properties.Header_libs, snapshotSuffix, snapshotHeaderSuffix) binaries := collectSnapshotMap(s.properties.Binaries, snapshotSuffix, snapshotBinarySuffix) objects := collectSnapshotMap(s.properties.Objects, snapshotSuffix, snapshotObjectSuffix) - staticLibs := collectSnapshotMap(s.properties.Static_libs, snapshotSuffix, snapshotStaticSuffix) - sharedLibs := collectSnapshotMap(s.properties.Shared_libs, snapshotSuffix, snapshotSharedSuffix) + staticLibs := collectSnapshotMap(s.properties.Static_libs, snapshotSuffix, SnapshotStaticSuffix) + sharedLibs := collectSnapshotMap(s.properties.Shared_libs, snapshotSuffix, SnapshotSharedSuffix) vndkLibs := collectSnapshotMap(s.properties.Vndk_libs, "", vndkSuffix) for k, v := range vndkLibs { sharedLibs[k] = v @@ -383,7 +383,7 @@ func recoverySnapshotFactory() android.Module { return snapshotFactory(recoverySnapshotImageSingleton) } -func snapshotFactory(image snapshotImage) android.Module { +func snapshotFactory(image SnapshotImage) android.Module { snapshot := &snapshot{} snapshot.image = image snapshot.AddProperties( @@ -393,7 +393,7 @@ func snapshotFactory(image snapshotImage) android.Module { return snapshot } -type baseSnapshotDecoratorProperties struct { +type BaseSnapshotDecoratorProperties struct { // snapshot version. Version string @@ -408,7 +408,7 @@ type baseSnapshotDecoratorProperties struct { ModuleSuffix string `blueprint:"mutated"` } -// baseSnapshotDecorator provides common basic functions for all snapshot modules, such as snapshot +// BaseSnapshotDecorator provides common basic functions for all snapshot modules, such as snapshot // version, snapshot arch, etc. It also adds a special suffix to Soong module name, so it doesn't // collide with source modules. e.g. the following example module, // @@ -420,40 +420,40 @@ type baseSnapshotDecoratorProperties struct { // } // // will be seen as "libbase.vendor_static.30.arm64" by Soong. -type baseSnapshotDecorator struct { - baseProperties baseSnapshotDecoratorProperties - image snapshotImage +type BaseSnapshotDecorator struct { + baseProperties BaseSnapshotDecoratorProperties + image SnapshotImage } -func (p *baseSnapshotDecorator) Name(name string) string { +func (p *BaseSnapshotDecorator) Name(name string) string { return name + p.NameSuffix() } -func (p *baseSnapshotDecorator) NameSuffix() string { - return getSnapshotNameSuffix(p.moduleSuffix(), p.version(), p.arch()) +func (p *BaseSnapshotDecorator) NameSuffix() string { + return getSnapshotNameSuffix(p.moduleSuffix(), p.Version(), p.Arch()) } -func (p *baseSnapshotDecorator) version() string { +func (p *BaseSnapshotDecorator) Version() string { return p.baseProperties.Version } -func (p *baseSnapshotDecorator) arch() string { +func (p *BaseSnapshotDecorator) Arch() string { return p.baseProperties.Target_arch } -func (p *baseSnapshotDecorator) moduleSuffix() string { +func (p *BaseSnapshotDecorator) moduleSuffix() string { return p.baseProperties.ModuleSuffix } -func (p *baseSnapshotDecorator) isSnapshotPrebuilt() bool { +func (p *BaseSnapshotDecorator) IsSnapshotPrebuilt() bool { return true } -func (p *baseSnapshotDecorator) snapshotAndroidMkSuffix() string { +func (p *BaseSnapshotDecorator) SnapshotAndroidMkSuffix() string { return p.baseProperties.Androidmk_suffix } -func (p *baseSnapshotDecorator) setSnapshotAndroidMkSuffix(ctx android.ModuleContext, variant string) { +func (p *BaseSnapshotDecorator) SetSnapshotAndroidMkSuffix(ctx android.ModuleContext, variant string) { // If there are any 2 or more variations among {core, product, vendor, recovery} // we have to add the androidmk suffix to avoid duplicate modules with the same // name. @@ -461,7 +461,7 @@ func (p *baseSnapshotDecorator) setSnapshotAndroidMkSuffix(ctx android.ModuleCon Mutator: "image", Variation: android.CoreVariation}) - if ctx.OtherModuleFarDependencyVariantExists(variations, ctx.Module().(*Module).BaseModuleName()) { + if ctx.OtherModuleFarDependencyVariantExists(variations, ctx.Module().(LinkableInterface).BaseModuleName()) { p.baseProperties.Androidmk_suffix = p.image.moduleNameSuffix() return } @@ -470,12 +470,12 @@ func (p *baseSnapshotDecorator) setSnapshotAndroidMkSuffix(ctx android.ModuleCon Mutator: "image", Variation: ProductVariationPrefix + ctx.DeviceConfig().PlatformVndkVersion()}) - if ctx.OtherModuleFarDependencyVariantExists(variations, ctx.Module().(*Module).BaseModuleName()) { + if ctx.OtherModuleFarDependencyVariantExists(variations, ctx.Module().(LinkableInterface).BaseModuleName()) { p.baseProperties.Androidmk_suffix = p.image.moduleNameSuffix() return } - images := []snapshotImage{VendorSnapshotImageSingleton, recoverySnapshotImageSingleton} + images := []SnapshotImage{VendorSnapshotImageSingleton, recoverySnapshotImageSingleton} for _, image := range images { if p.image == image { @@ -486,10 +486,10 @@ func (p *baseSnapshotDecorator) setSnapshotAndroidMkSuffix(ctx android.ModuleCon Variation: image.imageVariantName(ctx.DeviceConfig())}) if ctx.OtherModuleFarDependencyVariantExists(variations, - ctx.Module().(*Module).BaseModuleName()+ + ctx.Module().(LinkableInterface).BaseModuleName()+ getSnapshotNameSuffix( image.moduleNameSuffix()+variant, - p.version(), + p.Version(), ctx.DeviceConfig().Arches()[0].ArchType.String())) { p.baseProperties.Androidmk_suffix = p.image.moduleNameSuffix() return @@ -501,7 +501,7 @@ func (p *baseSnapshotDecorator) setSnapshotAndroidMkSuffix(ctx android.ModuleCon // Call this with a module suffix after creating a snapshot module, such as // vendorSnapshotSharedSuffix, recoverySnapshotBinarySuffix, etc. -func (p *baseSnapshotDecorator) init(m *Module, image snapshotImage, moduleSuffix string) { +func (p *BaseSnapshotDecorator) Init(m LinkableInterface, image SnapshotImage, moduleSuffix string) { p.image = image p.baseProperties.ModuleSuffix = image.moduleNameSuffix() + moduleSuffix m.AddProperties(&p.baseProperties) @@ -512,8 +512,8 @@ func (p *baseSnapshotDecorator) init(m *Module, image snapshotImage, moduleSuffi // vendorSnapshotLoadHook disables snapshots if it's not BOARD_VNDK_VERSION. // As vendor snapshot is only for vendor, such modules won't be used at all. -func vendorSnapshotLoadHook(ctx android.LoadHookContext, p *baseSnapshotDecorator) { - if p.version() != ctx.DeviceConfig().VndkVersion() { +func vendorSnapshotLoadHook(ctx android.LoadHookContext, p *BaseSnapshotDecorator) { + if p.Version() != ctx.DeviceConfig().VndkVersion() { ctx.Module().Disable() return } @@ -528,7 +528,7 @@ func vendorSnapshotLoadHook(ctx android.LoadHookContext, p *baseSnapshotDecorato // include directories, c flags, sanitize dependency information, etc. // // These modules are auto-generated by development/vendor_snapshot/update.py. -type snapshotLibraryProperties struct { +type SnapshotLibraryProperties struct { // Prebuilt file for each arch. Src *string `android:"arch_variant"` @@ -554,14 +554,14 @@ type snapshotSanitizer interface { } type snapshotLibraryDecorator struct { - baseSnapshotDecorator + BaseSnapshotDecorator *libraryDecorator - properties snapshotLibraryProperties + properties SnapshotLibraryProperties sanitizerProperties struct { CfiEnabled bool `blueprint:"mutated"` // Library flags for cfi variant. - Cfi snapshotLibraryProperties `android:"arch_variant"` + Cfi SnapshotLibraryProperties `android:"arch_variant"` } } @@ -570,9 +570,9 @@ func (p *snapshotLibraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) F return p.libraryDecorator.linkerFlags(ctx, flags) } -func (p *snapshotLibraryDecorator) matchesWithDevice(config android.DeviceConfig) bool { +func (p *snapshotLibraryDecorator) MatchesWithDevice(config android.DeviceConfig) bool { arches := config.Arches() - if len(arches) == 0 || arches[0].ArchType.String() != p.arch() { + if len(arches) == 0 || arches[0].ArchType.String() != p.Arch() { return false } if !p.header() && p.properties.Src == nil { @@ -587,14 +587,14 @@ func (p *snapshotLibraryDecorator) matchesWithDevice(config android.DeviceConfig func (p *snapshotLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path { var variant string if p.shared() { - variant = snapshotSharedSuffix + variant = SnapshotSharedSuffix } else if p.static() { - variant = snapshotStaticSuffix + variant = SnapshotStaticSuffix } else { variant = snapshotHeaderSuffix } - p.setSnapshotAndroidMkSuffix(ctx, variant) + p.SetSnapshotAndroidMkSuffix(ctx, variant) if p.header() { return p.libraryDecorator.link(ctx, flags, deps, objs) @@ -604,7 +604,7 @@ func (p *snapshotLibraryDecorator) link(ctx ModuleContext, flags Flags, deps Pat p.properties = p.sanitizerProperties.Cfi } - if !p.matchesWithDevice(ctx.DeviceConfig()) { + if !p.MatchesWithDevice(ctx.DeviceConfig()) { return nil } @@ -657,7 +657,7 @@ func (p *snapshotLibraryDecorator) link(ctx ModuleContext, flags Flags, deps Pat } func (p *snapshotLibraryDecorator) install(ctx ModuleContext, file android.Path) { - if p.matchesWithDevice(ctx.DeviceConfig()) && (p.shared() || p.static()) { + if p.MatchesWithDevice(ctx.DeviceConfig()) && (p.shared() || p.static()) { p.baseInstaller.install(ctx, file) } } @@ -687,7 +687,7 @@ func (p *snapshotLibraryDecorator) setSanitizerVariation(t SanitizerType, enable } } -func snapshotLibraryFactory(image snapshotImage, moduleSuffix string) (*Module, *snapshotLibraryDecorator) { +func snapshotLibraryFactory(image SnapshotImage, moduleSuffix string) (*Module, *snapshotLibraryDecorator) { module, library := NewLibrary(android.DeviceSupported) module.stl = nil @@ -710,7 +710,7 @@ func snapshotLibraryFactory(image snapshotImage, moduleSuffix string) (*Module, module.linker = prebuilt module.installer = prebuilt - prebuilt.init(module, image, moduleSuffix) + prebuilt.Init(module, image, moduleSuffix) module.AddProperties( &prebuilt.properties, &prebuilt.sanitizerProperties, @@ -724,7 +724,7 @@ func snapshotLibraryFactory(image snapshotImage, moduleSuffix string) (*Module, // 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, snapshotSharedSuffix) + module, prebuilt := snapshotLibraryFactory(VendorSnapshotImageSingleton, SnapshotSharedSuffix) prebuilt.libraryDecorator.BuildOnlyShared() return module.Init() } @@ -734,7 +734,7 @@ func VendorSnapshotSharedFactory() android.Module { // 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, snapshotSharedSuffix) + module, prebuilt := snapshotLibraryFactory(recoverySnapshotImageSingleton, SnapshotSharedSuffix) prebuilt.libraryDecorator.BuildOnlyShared() return module.Init() } @@ -744,7 +744,7 @@ func RecoverySnapshotSharedFactory() android.Module { // 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, snapshotStaticSuffix) + module, prebuilt := snapshotLibraryFactory(VendorSnapshotImageSingleton, SnapshotStaticSuffix) prebuilt.libraryDecorator.BuildOnlyStatic() return module.Init() } @@ -754,7 +754,7 @@ func VendorSnapshotStaticFactory() android.Module { // 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, snapshotStaticSuffix) + module, prebuilt := snapshotLibraryFactory(recoverySnapshotImageSingleton, SnapshotStaticSuffix) prebuilt.libraryDecorator.BuildOnlyStatic() return module.Init() } @@ -794,13 +794,13 @@ type snapshotBinaryProperties struct { } type snapshotBinaryDecorator struct { - baseSnapshotDecorator + BaseSnapshotDecorator *binaryDecorator properties snapshotBinaryProperties } -func (p *snapshotBinaryDecorator) matchesWithDevice(config android.DeviceConfig) bool { - if config.DeviceArch() != p.arch() { +func (p *snapshotBinaryDecorator) MatchesWithDevice(config android.DeviceConfig) bool { + if config.DeviceArch() != p.Arch() { return false } if p.properties.Src == nil { @@ -812,9 +812,9 @@ func (p *snapshotBinaryDecorator) matchesWithDevice(config android.DeviceConfig) // 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, snapshotBinarySuffix) + p.SetSnapshotAndroidMkSuffix(ctx, snapshotBinarySuffix) - if !p.matchesWithDevice(ctx.DeviceConfig()) { + if !p.MatchesWithDevice(ctx.DeviceConfig()) { return nil } @@ -852,7 +852,7 @@ func RecoverySnapshotBinaryFactory() android.Module { return snapshotBinaryFactory(recoverySnapshotImageSingleton, snapshotBinarySuffix) } -func snapshotBinaryFactory(image snapshotImage, 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) @@ -871,7 +871,7 @@ func snapshotBinaryFactory(image snapshotImage, moduleSuffix string) android.Mod module.stl = nil module.linker = prebuilt - prebuilt.init(module, image, moduleSuffix) + prebuilt.Init(module, image, moduleSuffix) module.AddProperties(&prebuilt.properties) return module.Init() } @@ -889,13 +889,13 @@ type vendorSnapshotObjectProperties struct { } type snapshotObjectLinker struct { - baseSnapshotDecorator + BaseSnapshotDecorator objectLinker properties vendorSnapshotObjectProperties } -func (p *snapshotObjectLinker) matchesWithDevice(config android.DeviceConfig) bool { - if config.DeviceArch() != p.arch() { +func (p *snapshotObjectLinker) MatchesWithDevice(config android.DeviceConfig) bool { + if config.DeviceArch() != p.Arch() { return false } if p.properties.Src == nil { @@ -907,9 +907,9 @@ func (p *snapshotObjectLinker) matchesWithDevice(config android.DeviceConfig) bo // 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, snapshotObjectSuffix) + p.SetSnapshotAndroidMkSuffix(ctx, snapshotObjectSuffix) - if !p.matchesWithDevice(ctx.DeviceConfig()) { + if !p.MatchesWithDevice(ctx.DeviceConfig()) { return nil } @@ -933,7 +933,7 @@ func VendorSnapshotObjectFactory() android.Module { } module.linker = prebuilt - prebuilt.init(module, VendorSnapshotImageSingleton, snapshotObjectSuffix) + prebuilt.Init(module, VendorSnapshotImageSingleton, snapshotObjectSuffix) module.AddProperties(&prebuilt.properties) return module.Init() } @@ -951,19 +951,19 @@ func RecoverySnapshotObjectFactory() android.Module { } module.linker = prebuilt - prebuilt.init(module, recoverySnapshotImageSingleton, snapshotObjectSuffix) + prebuilt.Init(module, recoverySnapshotImageSingleton, snapshotObjectSuffix) module.AddProperties(&prebuilt.properties) return module.Init() } -type snapshotInterface interface { - matchesWithDevice(config android.DeviceConfig) bool - isSnapshotPrebuilt() bool - version() string - snapshotAndroidMkSuffix() string +type SnapshotInterface interface { + MatchesWithDevice(config android.DeviceConfig) bool + IsSnapshotPrebuilt() bool + Version() string + SnapshotAndroidMkSuffix() string } -var _ snapshotInterface = (*vndkPrebuiltLibraryDecorator)(nil) -var _ snapshotInterface = (*snapshotLibraryDecorator)(nil) -var _ snapshotInterface = (*snapshotBinaryDecorator)(nil) -var _ snapshotInterface = (*snapshotObjectLinker)(nil) +var _ SnapshotInterface = (*vndkPrebuiltLibraryDecorator)(nil) +var _ SnapshotInterface = (*snapshotLibraryDecorator)(nil) +var _ SnapshotInterface = (*snapshotBinaryDecorator)(nil) +var _ SnapshotInterface = (*snapshotObjectLinker)(nil) diff --git a/cc/snapshot_utils.go b/cc/snapshot_utils.go index 7b62603ef..a6c8ed522 100644 --- a/cc/snapshot_utils.go +++ b/cc/snapshot_utils.go @@ -109,7 +109,7 @@ func ShouldCollectHeadersForSnapshot(ctx android.ModuleContext, m LinkableInterf return ctx.Config().VndkSnapshotBuildArtifacts() } - for _, image := range []snapshotImage{VendorSnapshotImageSingleton, recoverySnapshotImageSingleton} { + for _, image := range []SnapshotImage{VendorSnapshotImageSingleton, recoverySnapshotImageSingleton} { if isSnapshotAware(ctx.DeviceConfig(), m, image.isProprietaryPath(ctx.ModuleDir(), ctx.DeviceConfig()), apexInfo, image) { return true } diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go index 2c29a89aa..04aab4245 100644 --- a/cc/vendor_snapshot.go +++ b/cc/vendor_snapshot.go @@ -82,7 +82,7 @@ type snapshotSingleton struct { // Implementation of the image interface specific to the image // associated with this snapshot (e.g., specific to the vendor image, // recovery image, etc.). - image snapshotImage + image SnapshotImage // Whether this singleton is for fake snapshot or not. // Fake snapshot is a snapshot whose prebuilt binaries and headers are empty. @@ -147,7 +147,7 @@ func isRecoveryProprietaryModule(ctx android.BaseModuleContext) bool { } // Determines if the module is a candidate for snapshot. -func isSnapshotAware(cfg android.DeviceConfig, m LinkableInterface, inProprietaryPath bool, apexInfo android.ApexInfo, image snapshotImage) bool { +func isSnapshotAware(cfg android.DeviceConfig, m LinkableInterface, inProprietaryPath bool, apexInfo android.ApexInfo, image SnapshotImage) bool { if !m.Enabled() || m.HiddenFromMake() { return false } diff --git a/cc/vndk.go b/cc/vndk.go index 6a56c34db..dd1c3e14b 100644 --- a/cc/vndk.go +++ b/cc/vndk.go @@ -360,7 +360,7 @@ func IsForVndkApex(mctx android.BottomUpMutatorContext, m *Module) bool { // prebuilt vndk modules should match with device // TODO(b/142675459): Use enabled: to select target device in vndk_prebuilt_shared // When b/142675459 is landed, remove following check - if p, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok && !p.matchesWithDevice(mctx.DeviceConfig()) { + if p, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok && !p.MatchesWithDevice(mctx.DeviceConfig()) { return false } diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go index fc4412a75..141f43874 100644 --- a/cc/vndk_prebuilt.go +++ b/cc/vndk_prebuilt.go @@ -82,7 +82,7 @@ func (p *vndkPrebuiltLibraryDecorator) Name(name string) string { } func (p *vndkPrebuiltLibraryDecorator) NameSuffix() string { - suffix := p.version() + suffix := p.Version() if p.arch() != "" { suffix += "." + p.arch() } @@ -92,7 +92,7 @@ func (p *vndkPrebuiltLibraryDecorator) NameSuffix() string { return vndkSuffix + suffix } -func (p *vndkPrebuiltLibraryDecorator) version() string { +func (p *vndkPrebuiltLibraryDecorator) Version() string { return String(p.properties.Version) } @@ -107,7 +107,7 @@ func (p *vndkPrebuiltLibraryDecorator) binderBit() string { return "64" } -func (p *vndkPrebuiltLibraryDecorator) snapshotAndroidMkSuffix() string { +func (p *vndkPrebuiltLibraryDecorator) SnapshotAndroidMkSuffix() string { return ".vendor" } @@ -133,7 +133,7 @@ func (p *vndkPrebuiltLibraryDecorator) singleSourcePath(ctx ModuleContext) andro func (p *vndkPrebuiltLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path { - if !p.matchesWithDevice(ctx.DeviceConfig()) { + if !p.MatchesWithDevice(ctx.DeviceConfig()) { ctx.Module().HideFromMake() return nil } @@ -163,7 +163,7 @@ func (p *vndkPrebuiltLibraryDecorator) link(ctx ModuleContext, p.androidMkSuffix = p.NameSuffix() vndkVersion := ctx.DeviceConfig().VndkVersion() - if vndkVersion == p.version() { + if vndkVersion == p.Version() { p.androidMkSuffix = "" } @@ -184,7 +184,7 @@ func (p *vndkPrebuiltLibraryDecorator) link(ctx ModuleContext, return nil } -func (p *vndkPrebuiltLibraryDecorator) matchesWithDevice(config android.DeviceConfig) bool { +func (p *vndkPrebuiltLibraryDecorator) MatchesWithDevice(config android.DeviceConfig) bool { arches := config.Arches() if len(arches) == 0 || arches[0].ArchType.String() != p.arch() { return false @@ -202,7 +202,7 @@ func (p *vndkPrebuiltLibraryDecorator) nativeCoverage() bool { return false } -func (p *vndkPrebuiltLibraryDecorator) isSnapshotPrebuilt() bool { +func (p *vndkPrebuiltLibraryDecorator) IsSnapshotPrebuilt() bool { return true } From 3149e6ed1882786fc9e1defd0b5540c0147a0209 Mon Sep 17 00:00:00 2001 From: Ivan Lozano Date: Tue, 1 Jun 2021 15:09:53 -0400 Subject: [PATCH 3/3] Rust rlib vendor snapshot support. Adds support for snapshotting Rust rlibs. This allows us vendor-specific code that uses rlib-only linkage until dylib snapshot support is added. Bug: 184042776 Test: m nothing # new Soong tests pass Test: Example test Rust vendor module builds Test: m dist vendor-snapshot # includes rlibs Change-Id: I4976d3e1efec0ee778cc97730d45be471dffb678 --- cc/snapshot_prebuilt.go | 10 +- cc/vendor_snapshot.go | 6 +- rust/Android.bp | 1 + rust/image.go | 15 +- rust/library.go | 12 +- rust/rust.go | 32 +- rust/rust_test.go | 16 +- rust/snapshot_prebuilt.go | 121 ++++++ rust/snapshot_utils.go | 5 +- rust/testing.go | 4 + rust/vendor_snapshot_test.go | 786 ++++++++++++++++++++++++++++++++++- 11 files changed, 964 insertions(+), 44 deletions(-) create mode 100644 rust/snapshot_prebuilt.go 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) + } +}