diff --git a/rust/binary.go b/rust/binary.go index 0334accef..df489169b 100644 --- a/rust/binary.go +++ b/rust/binary.go @@ -119,6 +119,7 @@ func (binary *binaryDecorator) compile(ctx ModuleContext, flags Flags, deps Path outputFile := android.PathForModuleOut(ctx, fileName) flags.RustFlags = append(flags.RustFlags, deps.depFlags...) + flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...) flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...) TransformSrcToBinary(ctx, srcPath, deps, flags, outputFile, deps.linkDirs) diff --git a/rust/compiler.go b/rust/compiler.go index c92182420..586063e91 100644 --- a/rust/compiler.go +++ b/rust/compiler.go @@ -96,7 +96,11 @@ type BaseCompilerProperties struct { // list of C shared library dependencies Shared_libs []string `android:"arch_variant"` - // list of C static library dependencies + // list of C static library dependencies. Note, static libraries prefixed by "lib" will be passed to rustc + // along with "-lstatic=". This will bundle the static library into rlib/static libraries so dependents do + // not need to also declare the static library as a dependency. Static libraries which are not prefixed by "lib" + // cannot be passed to rustc with this flag and will not be bundled into rlib/static libraries, and thus must + // be redeclared in dependents. Static_libs []string `android:"arch_variant"` // crate name, required for modules which produce Rust libraries: rust_library, rust_ffi and SourceProvider diff --git a/rust/library.go b/rust/library.go index b5749a2de..7ff13ec66 100644 --- a/rust/library.go +++ b/rust/library.go @@ -443,6 +443,7 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa } flags.RustFlags = append(flags.RustFlags, deps.depFlags...) + flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...) flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...) if library.dylib() { @@ -482,7 +483,6 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa if library.rlib() || library.dylib() { library.flagExporter.exportLinkDirs(deps.linkDirs...) - library.flagExporter.exportDepFlags(deps.depFlags...) library.flagExporter.exportLinkObjects(deps.linkObjects...) } diff --git a/rust/rust.go b/rust/rust.go index 504b7a9bd..e1af77692 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -280,10 +280,15 @@ type PathDeps struct { SharedLibDeps android.Paths StaticLibs android.Paths ProcMacros RustLibraries - linkDirs []string - depFlags []string - linkObjects []string - //ReexportedDeps android.Paths + + // depFlags and depLinkFlags are rustc and linker (clang) flags. + depFlags []string + depLinkFlags []string + + // linkDirs are link paths passed via -L to rustc. linkObjects are objects passed directly to the linker. + // Both of these are exported and propagate to dependencies. + linkDirs []string + linkObjects []string // Used by bindgen modules which call clang depClangFlags []string @@ -328,12 +333,10 @@ type compiler interface { type exportedFlagsProducer interface { exportLinkDirs(...string) - exportDepFlags(...string) exportLinkObjects(...string) } type flagExporter struct { - depFlags []string linkDirs []string linkObjects []string } @@ -342,17 +345,12 @@ func (flagExporter *flagExporter) exportLinkDirs(dirs ...string) { flagExporter.linkDirs = android.FirstUniqueStrings(append(flagExporter.linkDirs, dirs...)) } -func (flagExporter *flagExporter) exportDepFlags(flags ...string) { - flagExporter.depFlags = android.FirstUniqueStrings(append(flagExporter.depFlags, flags...)) -} - func (flagExporter *flagExporter) exportLinkObjects(flags ...string) { flagExporter.linkObjects = android.FirstUniqueStrings(append(flagExporter.linkObjects, flags...)) } func (flagExporter *flagExporter) setProvider(ctx ModuleContext) { ctx.SetProvider(FlagExporterInfoProvider, FlagExporterInfo{ - Flags: flagExporter.depFlags, LinkDirs: flagExporter.linkDirs, LinkObjects: flagExporter.linkObjects, }) @@ -898,8 +896,21 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { exportDep := false switch { case cc.IsStaticDepTag(depTag): - depPaths.linkDirs = append(depPaths.linkDirs, linkPath) + // Link cc static libraries using "-lstatic" so rustc can reason about how to handle these + // (for example, bundling them into rlibs). + // + // rustc does not support linking libraries with the "-l" flag unless they are prefixed by "lib". + // If we need to link a library that isn't prefixed by "lib", we'll just link to it directly through + // linkObjects; such a library may need to be redeclared by static dependents. + if libName, ok := libNameFromFilePath(linkObject.Path()); ok { + depPaths.depFlags = append(depPaths.depFlags, "-lstatic="+libName) + } + + // Add this to linkObjects to pass the library directly to the linker as well. This propagates + // to dependencies to avoid having to redeclare static libraries for dependents of the dylib variant. depPaths.linkObjects = append(depPaths.linkObjects, linkObject.String()) + depPaths.linkDirs = append(depPaths.linkDirs, linkPath) + exportedInfo := ctx.OtherModuleProvider(dep, cc.FlagExporterInfoProvider).(cc.FlagExporterInfo) depPaths.depIncludePaths = append(depPaths.depIncludePaths, exportedInfo.IncludeDirs...) depPaths.depSystemIncludePaths = append(depPaths.depSystemIncludePaths, exportedInfo.SystemIncludeDirs...) @@ -1213,6 +1224,16 @@ func (mod *Module) IsInstallableToApex() bool { return false } +// If a library file has a "lib" prefix, extract the library name without the prefix. +func libNameFromFilePath(filepath android.Path) (string, bool) { + libName := strings.TrimSuffix(filepath.Base(), filepath.Ext()) + if strings.HasPrefix(libName, "lib") { + libName = libName[3:] + return libName, true + } + return "", false +} + var Bool = proptools.Bool var BoolDefault = proptools.BoolDefault var String = proptools.String diff --git a/rust/rust_test.go b/rust/rust_test.go index abc9af9b1..a32c6a7f8 100644 --- a/rust/rust_test.go +++ b/rust/rust_test.go @@ -230,6 +230,7 @@ func TestDepsTracking(t *testing.T) { } `) module := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module) + rustc := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Rule("rustc") // Since dependencies are added to AndroidMk* properties, we can check these to see if they've been picked up. if !android.InList("libdylib", module.Properties.AndroidMkDylibs) { @@ -251,6 +252,11 @@ func TestDepsTracking(t *testing.T) { if !android.InList("libstatic", module.Properties.AndroidMkStaticLibs) { t.Errorf("Static library dependency not detected (dependency missing from AndroidMkStaticLibs)") } + + if !strings.Contains(rustc.Args["rustcFlags"], "-lstatic=static") { + t.Errorf("-lstatic flag not being passed to rustc for static library") + } + } func TestSourceProviderDeps(t *testing.T) {