From 7b0781d14c9054552ce5f83420ac92fda1d31e8b Mon Sep 17 00:00:00 2001 From: Ivan Lozano Date: Wed, 3 Nov 2021 15:30:18 -0400 Subject: [PATCH] rust: Emit toc files for cdylibs Write toc files that list the exported symbols so dependents are only rebuilt if the exported symbols change. This exports the CC function TransformSharedObjectToToc, and also removes an unused arg from its signature. Bug: 178185435 Test: New Soong test passes. Test: m Change-Id: I7ab69bf7e7f32f25eb4c7ca9d18d877dac1511db --- cc/builder.go | 3 +-- cc/library.go | 2 +- cc/prebuilt.go | 4 +--- cc/snapshot_prebuilt.go | 3 +-- cc/vndk_prebuilt.go | 3 +-- rust/androidmk.go | 8 ++++++-- rust/builder.go | 4 ++-- rust/library.go | 20 ++++++++++++++++++-- rust/library_test.go | 20 ++++++++++++++++++++ rust/rust.go | 4 ++-- 10 files changed, 53 insertions(+), 18 deletions(-) diff --git a/cc/builder.go b/cc/builder.go index abd5f1db9..72c2fa555 100644 --- a/cc/builder.go +++ b/cc/builder.go @@ -949,8 +949,7 @@ func sourceAbiDiff(ctx android.ModuleContext, inputDump android.Path, referenceD } // Generate a rule for extracting a table of contents from a shared library (.so) -func transformSharedObjectToToc(ctx android.ModuleContext, inputFile android.Path, - outputFile android.WritablePath, flags builderFlags) { +func TransformSharedObjectToToc(ctx android.ModuleContext, inputFile android.Path, outputFile android.WritablePath) { var format string if ctx.Darwin() { diff --git a/cc/library.go b/cc/library.go index c3f7305bf..a394409f9 100644 --- a/cc/library.go +++ b/cc/library.go @@ -1377,7 +1377,7 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext, // depending on a table of contents file instead of the library itself. tocFile := outputFile.ReplaceExtension(ctx, flags.Toolchain.ShlibSuffix()[1:]+".toc") library.tocFile = android.OptionalPathForPath(tocFile) - transformSharedObjectToToc(ctx, outputFile, tocFile, builderFlags) + TransformSharedObjectToToc(ctx, outputFile, tocFile) stripFlags := flagsToStripFlags(flags) needsStrip := library.stripper.NeedsStrip(ctx) diff --git a/cc/prebuilt.go b/cc/prebuilt.go index 3401e3658..16945ac69 100644 --- a/cc/prebuilt.go +++ b/cc/prebuilt.go @@ -114,8 +114,6 @@ func (p *prebuiltLibraryLinker) link(ctx ModuleContext, // TODO(ccross): verify shared library dependencies srcs := p.prebuiltSrcs(ctx) if len(srcs) > 0 { - builderFlags := flagsToBuilderFlags(flags) - if len(srcs) > 1 { ctx.PropertyErrorf("srcs", "multiple prebuilt source files") return nil @@ -152,7 +150,7 @@ func (p *prebuiltLibraryLinker) link(ctx ModuleContext, // depending on a table of contents file instead of the library itself. tocFile := android.PathForModuleOut(ctx, libName+".toc") p.tocFile = android.OptionalPathForPath(tocFile) - transformSharedObjectToToc(ctx, outputFile, tocFile, builderFlags) + TransformSharedObjectToToc(ctx, outputFile, tocFile) if ctx.Windows() && p.properties.Windows_import_lib != nil { // Consumers of this library actually links to the import library in build diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go index 9570664c7..d9b0bbe47 100644 --- a/cc/snapshot_prebuilt.go +++ b/cc/snapshot_prebuilt.go @@ -476,13 +476,12 @@ func (p *snapshotLibraryDecorator) link(ctx ModuleContext, flags Flags, deps Pat if p.shared() { libName := in.Base() - builderFlags := flagsToBuilderFlags(flags) // Optimize out relinking against shared libraries whose interface hasn't changed by // depending on a table of contents file instead of the library itself. tocFile := android.PathForModuleOut(ctx, libName+".toc") p.tocFile = android.OptionalPathForPath(tocFile) - transformSharedObjectToToc(ctx, in, tocFile, builderFlags) + TransformSharedObjectToToc(ctx, in, tocFile) ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{ SharedLibrary: in, diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go index da34f3684..31b6d10dd 100644 --- a/cc/vndk_prebuilt.go +++ b/cc/vndk_prebuilt.go @@ -144,7 +144,6 @@ func (p *vndkPrebuiltLibraryDecorator) link(ctx ModuleContext, // current VNDK prebuilts are only shared libs. in := p.singleSourcePath(ctx) - builderFlags := flagsToBuilderFlags(flags) p.unstrippedOutputFile = in libName := in.Base() if p.stripper.NeedsStrip(ctx) { @@ -158,7 +157,7 @@ func (p *vndkPrebuiltLibraryDecorator) link(ctx ModuleContext, // depending on a table of contents file instead of the library itself. tocFile := android.PathForModuleOut(ctx, libName+".toc") p.tocFile = android.OptionalPathForPath(tocFile) - transformSharedObjectToToc(ctx, in, tocFile, builderFlags) + TransformSharedObjectToToc(ctx, in, tocFile) p.androidMkSuffix = p.NameSuffix() diff --git a/rust/androidmk.go b/rust/androidmk.go index 630805a85..e429416ab 100644 --- a/rust/androidmk.go +++ b/rust/androidmk.go @@ -137,12 +137,16 @@ func (library *libraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.An } else if library.shared() { ret.Class = "SHARED_LIBRARIES" } - if library.distFile.Valid() { ret.DistFiles = android.MakeDefaultDistFiles(library.distFile.Path()) } + ret.ExtraEntries = append(ret.ExtraEntries, + func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { + if library.tocFile.Valid() { + entries.SetString("LOCAL_SOONG_TOC", library.tocFile.String()) + } + }) } - func (procMacro *procMacroDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) { ctx.SubAndroidMk(ret, procMacro.baseCompiler) diff --git a/rust/builder.go b/rust/builder.go index f79cf9b12..6f203476e 100644 --- a/rust/builder.go +++ b/rust/builder.go @@ -185,7 +185,7 @@ func rustEnvVars(ctx ModuleContext, deps PathDeps) []string { } func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, flags Flags, - outputFile android.WritablePath, crate_type string) buildOutput { + outputFile android.WritablePath, crateType string) buildOutput { var inputs android.Paths var implicits android.Paths @@ -204,7 +204,7 @@ func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, fl // Collect rustc flags rustcFlags = append(rustcFlags, flags.GlobalRustFlags...) rustcFlags = append(rustcFlags, flags.RustFlags...) - rustcFlags = append(rustcFlags, "--crate-type="+crate_type) + rustcFlags = append(rustcFlags, "--crate-type="+crateType) if crateName != "" { rustcFlags = append(rustcFlags, "--crate-name="+crateName) } diff --git a/rust/library.go b/rust/library.go index 38dae4d33..ea14e6d48 100644 --- a/rust/library.go +++ b/rust/library.go @@ -102,6 +102,9 @@ type libraryDecorator struct { sourceProvider SourceProvider collectedSnapshotHeaders android.Paths + + // table-of-contents file for cdylib crates to optimize out relinking when possible + tocFile android.OptionalPath } type libraryInterface interface { @@ -137,12 +140,18 @@ type libraryInterface interface { BuildOnlyDylib() BuildOnlyStatic() BuildOnlyShared() + + toc() android.OptionalPath } func (library *libraryDecorator) nativeCoverage() bool { return true } +func (library *libraryDecorator) toc() android.OptionalPath { + return library.tocFile +} + func (library *libraryDecorator) rlib() bool { return library.MutatedProperties.VariantIsRlib } @@ -519,9 +528,16 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa } if library.shared() { + // Optimize out relinking against shared libraries whose interface hasn't changed by + // depending on a table of contents file instead of the library itself. + tocFile := outputFile.ReplaceExtension(ctx, flags.Toolchain.SharedLibSuffix()[1:]+".toc") + library.tocFile = android.OptionalPathForPath(tocFile) + cc.TransformSharedObjectToToc(ctx, outputFile, tocFile) + ctx.SetProvider(cc.SharedLibraryInfoProvider, cc.SharedLibraryInfo{ - SharedLibrary: outputFile, - Target: ctx.Target(), + TableOfContents: android.OptionalPathForPath(tocFile), + SharedLibrary: outputFile, + Target: ctx.Target(), }) } diff --git a/rust/library_test.go b/rust/library_test.go index cb4ef7eec..edb9c89b6 100644 --- a/rust/library_test.go +++ b/rust/library_test.go @@ -160,6 +160,26 @@ func TestSharedLibrary(t *testing.T) { } } +func TestSharedLibraryToc(t *testing.T) { + ctx := testRust(t, ` + rust_ffi_shared { + name: "libfoo", + srcs: ["foo.rs"], + crate_name: "foo", + } + cc_binary { + name: "fizzbuzz", + shared_libs: ["libfoo"], + }`) + + fizzbuzz := ctx.ModuleForTests("fizzbuzz", "android_arm64_armv8-a").Rule("ld") + + if !android.SuffixInList(fizzbuzz.Implicits.Strings(), "libfoo.so.toc") { + t.Errorf("missing expected libfoo.so.toc implicit dependency, instead found: %#v", + fizzbuzz.Implicits.Strings()) + } +} + func TestStaticLibraryLinkage(t *testing.T) { ctx := testRust(t, ` rust_ffi_static { diff --git a/rust/rust.go b/rust/rust.go index c465cb609..c159e4a87 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -281,8 +281,8 @@ func (mod *Module) Object() bool { func (mod *Module) Toc() android.OptionalPath { if mod.compiler != nil { - if _, ok := mod.compiler.(libraryInterface); ok { - return android.OptionalPath{} + if lib, ok := mod.compiler.(libraryInterface); ok { + return lib.toc() } } panic(fmt.Errorf("Toc() called on non-library module: %q", mod.BaseModuleName()))