diff --git a/cc/linkable.go b/cc/linkable.go index 13b732bf4..6aa238b24 100644 --- a/cc/linkable.go +++ b/cc/linkable.go @@ -158,8 +158,16 @@ func SharedDepTag() blueprint.DependencyTag { } // StaticDepTag returns the dependency tag for any C++ static libraries. -func StaticDepTag() blueprint.DependencyTag { - return libraryDependencyTag{Kind: staticLibraryDependency} +func StaticDepTag(wholeStatic bool) blueprint.DependencyTag { + return libraryDependencyTag{Kind: staticLibraryDependency, wholeStatic: wholeStatic} +} + +// IsWholeStaticLib whether a dependency tag is a whole static library dependency. +func IsWholeStaticLib(depTag blueprint.DependencyTag) bool { + if tag, ok := depTag.(libraryDependencyTag); ok { + return tag.wholeStatic + } + return false } // HeaderDepTag returns the dependency tag for any C++ "header-only" libraries. diff --git a/rust/compiler.go b/rust/compiler.go index 200af9061..41b73719a 100644 --- a/rust/compiler.go +++ b/rust/compiler.go @@ -97,13 +97,25 @@ type BaseCompilerProperties struct { // list of C shared library dependencies Shared_libs []string `android:"arch_variant"` - // 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. + // list of C static library dependencies. These dependencies do not normally propagate to dependents + // and may need to be redeclared. See whole_static_libs for bundling static dependencies into a library. Static_libs []string `android:"arch_variant"` + // Similar to static_libs, but will bundle the static library dependency into a library. This is helpful + // to avoid having to redeclare the dependency for dependents of this library, but in some cases may also + // result in bloat if multiple dependencies all include the same static library whole. + // + // The common use case for this is when the static library is unlikely to be a dependency of other modules to avoid + // having to redeclare the static library dependency for every dependent module. + // If you are not sure what to, for rust_library modules most static dependencies should go in static_libraries, + // and for rust_ffi modules most static dependencies should go into whole_static_libraries. + // + // For rust_ffi static variants, these libraries will be included in the resulting static library archive. + // + // For rust_library rlib variants, these libraries will be bundled into the resulting rlib library. This will + // include all of the static libraries symbols in any dylibs or binaries which use this rlib as well. + Whole_static_libs []string `android:"arch_variant"` + // crate name, required for modules which produce Rust libraries: rust_library, rust_ffi and SourceProvider // modules which create library variants (rust_bindgen). This must be the expected extern crate name used in // source, and is required to conform to an enforced format matching library output files (if the output file is @@ -266,6 +278,7 @@ func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps { deps.Rustlibs = append(deps.Rustlibs, compiler.Properties.Rustlibs...) deps.ProcMacros = append(deps.ProcMacros, compiler.Properties.Proc_macros...) deps.StaticLibs = append(deps.StaticLibs, compiler.Properties.Static_libs...) + deps.WholeStaticLibs = append(deps.WholeStaticLibs, compiler.Properties.Whole_static_libs...) deps.SharedLibs = append(deps.SharedLibs, compiler.Properties.Shared_libs...) if !Bool(compiler.Properties.No_stdlibs) { diff --git a/rust/rust.go b/rust/rust.go index 17ff6252f..f0d0e361c 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -273,14 +273,15 @@ func (mod *Module) SplitPerApiLevel() bool { } type Deps struct { - Dylibs []string - Rlibs []string - Rustlibs []string - Stdlibs []string - ProcMacros []string - SharedLibs []string - StaticLibs []string - HeaderLibs []string + Dylibs []string + Rlibs []string + Rustlibs []string + Stdlibs []string + ProcMacros []string + SharedLibs []string + StaticLibs []string + WholeStaticLibs []string + HeaderLibs []string CrtBegin, CrtEnd string } @@ -755,7 +756,7 @@ func (mod *Module) deps(ctx DepsContext) Deps { deps.ProcMacros = android.LastUniqueStrings(deps.ProcMacros) deps.SharedLibs = android.LastUniqueStrings(deps.SharedLibs) deps.StaticLibs = android.LastUniqueStrings(deps.StaticLibs) - + deps.WholeStaticLibs = android.LastUniqueStrings(deps.WholeStaticLibs) return deps } @@ -915,16 +916,13 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { exportDep := false switch { case cc.IsStaticDepTag(depTag): - // Only pass -lstatic for rlibs as it results in dylib bloat. - if lib, ok := ctx.Module().(*Module).compiler.(libraryInterface); ok && lib.rlib() { - // 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 cc.IsWholeStaticLib(depTag) { + // rustc will bundle static libraries when they're passed with "-lstatic=". This will fail + // if the library is not prefixed by "lib". if libName, ok := libNameFromFilePath(linkObject.Path()); ok { depPaths.depFlags = append(depPaths.depFlags, "-lstatic="+libName) + } else { + ctx.ModuleErrorf("'%q' cannot be listed as a whole_static_library in Rust modules unless the output is prefixed by 'lib'", depName, ctx.ModuleName()) } } @@ -1103,7 +1101,10 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) { cc.SharedDepTag(), deps.SharedLibs...) actx.AddVariationDependencies(append(commonDepVariations, blueprint.Variation{Mutator: "link", Variation: "static"}), - cc.StaticDepTag(), deps.StaticLibs...) + cc.StaticDepTag(false), deps.StaticLibs...) + actx.AddVariationDependencies(append(commonDepVariations, + blueprint.Variation{Mutator: "link", Variation: "static"}), + cc.StaticDepTag(true), deps.WholeStaticLibs...) actx.AddVariationDependencies(nil, cc.HeaderDepTag(), deps.HeaderLibs...) diff --git a/rust/rust_test.go b/rust/rust_test.go index bed28ec8f..418bd93a4 100644 --- a/rust/rust_test.go +++ b/rust/rust_test.go @@ -149,6 +149,11 @@ func TestDepsTracking(t *testing.T) { srcs: ["foo.rs"], crate_name: "static", } + rust_ffi_host_static { + name: "libwholestatic", + srcs: ["foo.rs"], + crate_name: "wholestatic", + } rust_ffi_host_shared { name: "libshared", srcs: ["foo.rs"], @@ -164,6 +169,7 @@ func TestDepsTracking(t *testing.T) { srcs: ["foo.rs"], crate_name: "rlib", static_libs: ["libstatic"], + whole_static_libs: ["libwholestatic"], } rust_proc_macro { name: "libpm", @@ -204,8 +210,8 @@ func TestDepsTracking(t *testing.T) { 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") + if !strings.Contains(rustc.Args["rustcFlags"], "-lstatic=wholestatic") { + t.Errorf("-lstatic flag not being passed to rustc for static library %#v", rustc.Args["rustcFlags"]) } }