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 <toc file path>
Change-Id: I7ab69bf7e7f32f25eb4c7ca9d18d877dac1511db
diff --git a/rust/androidmk.go b/rust/androidmk.go
index 630805a..e429416 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -137,12 +137,16 @@
} 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 f79cf9b..6f20347 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -185,7 +185,7 @@
}
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 @@
// 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 38dae4d..ea14e6d 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -102,6 +102,9 @@
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 @@
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 @@
}
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 cb4ef7e..edb9c89 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -160,6 +160,26 @@
}
}
+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 c465cb6..c159e4a 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -281,8 +281,8 @@
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()))