diff --git a/rust/binary.go b/rust/binary.go index 2758ae077..af39d383d 100644 --- a/rust/binary.go +++ b/rust/binary.go @@ -28,6 +28,12 @@ type BinaryCompilerProperties struct { // Also link libstd as an rlib as well on device targets. // Note: This is the default behavior for host targets. Prefer_rlib *bool `android:"arch_variant"` + + // Builds this binary as a static binary. Implies prefer_rlib true. + // + // Static executables currently only support for bionic targets. Non-bionic targets will not produce a fully static + // binary, but will still implicitly imply prefer_rlib true. + Static_executable *bool `android:"arch_variant"` } type binaryDecorator struct { @@ -72,6 +78,11 @@ func (binary *binaryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Fla "-Wl,--gc-sections", "-Wl,-z,nocopyreloc", "-Wl,--no-undefined-version") + + if Bool(binary.Properties.Static_executable) { + flags.LinkFlags = append(flags.LinkFlags, "-static") + flags.RustFlags = append(flags.RustFlags, "-C relocation-model=static") + } } return flags @@ -81,8 +92,12 @@ func (binary *binaryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps { deps = binary.baseCompiler.compilerDeps(ctx, deps) if ctx.toolchain().Bionic() { - deps = bionicDeps(deps) - deps.CrtBegin = "crtbegin_dynamic" + deps = bionicDeps(deps, Bool(binary.Properties.Static_executable)) + if Bool(binary.Properties.Static_executable) { + deps.CrtBegin = "crtbegin_static" + } else { + deps.CrtBegin = "crtbegin_dynamic" + } deps.CrtEnd = "crtend_android" } @@ -99,6 +114,10 @@ func (binary *binaryDecorator) nativeCoverage() bool { return true } +func (binary *binaryDecorator) preferRlib() bool { + return Bool(binary.Properties.Prefer_rlib) || Bool(binary.Properties.Static_executable) +} + func (binary *binaryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path { fileName := binary.getStem(ctx) + ctx.toolchain().ExecutableSuffix() srcPath, _ := srcPathFromModuleSrcs(ctx, binary.baseCompiler.Properties.Srcs) @@ -135,7 +154,7 @@ func (binary *binaryDecorator) coverageOutputZipPath() android.OptionalPath { func (binary *binaryDecorator) autoDep(ctx BaseModuleContext) autoDep { // Binaries default to dylib dependencies for device, rlib for host. - if Bool(binary.Properties.Prefer_rlib) { + if binary.preferRlib() { return rlibAutoDep } if ctx.Device() { @@ -146,7 +165,7 @@ func (binary *binaryDecorator) autoDep(ctx BaseModuleContext) autoDep { } func (binary *binaryDecorator) stdLinkage(ctx *depsContext) RustLinkage { - if Bool(binary.Properties.Prefer_rlib) { + if binary.preferRlib() { return RlibLinkage } return binary.baseCompiler.stdLinkage(ctx) diff --git a/rust/binary_test.go b/rust/binary_test.go index f31a7fcda..b44a5bc71 100644 --- a/rust/binary_test.go +++ b/rust/binary_test.go @@ -114,6 +114,34 @@ func TestBinaryFlags(t *testing.T) { } } +func TestStaticBinaryFlags(t *testing.T) { + ctx := testRust(t, ` + rust_binary { + name: "fizz", + srcs: ["foo.rs"], + static_executable: true, + }`) + + fizzOut := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Output("fizz") + fizzMod := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Module().(*Module) + + flags := fizzOut.Args["rustcFlags"] + linkFlags := fizzOut.Args["linkFlags"] + if !strings.Contains(flags, "-C relocation-model=static") { + t.Errorf("static binary missing '-C relocation-model=static' in rustcFlags, found: %#v", flags) + } + if !strings.Contains(linkFlags, "-static") { + t.Errorf("static binary missing '-static' in linkFlags, found: %#v", flags) + } + + if !android.InList("libc", fizzMod.Properties.AndroidMkStaticLibs) { + t.Errorf("static binary not linking against libc as a static library") + } + if len(fizzMod.Properties.AndroidMkSharedLibs) > 0 { + t.Errorf("static binary incorrectly linking against shared libraries") + } +} + func TestLinkObjects(t *testing.T) { ctx := testRust(t, ` rust_binary { diff --git a/rust/bindgen.go b/rust/bindgen.go index d8d126d37..e5112de5d 100644 --- a/rust/bindgen.go +++ b/rust/bindgen.go @@ -267,7 +267,7 @@ func NewRustBindgen(hod android.HostOrDeviceSupported) (*Module, *bindgenDecorat func (b *bindgenDecorator) SourceProviderDeps(ctx DepsContext, deps Deps) Deps { deps = b.BaseSourceProvider.SourceProviderDeps(ctx, deps) if ctx.toolchain().Bionic() { - deps = bionicDeps(deps) + deps = bionicDeps(deps, false) } deps.SharedLibs = append(deps.SharedLibs, b.Properties.Shared_libs...) diff --git a/rust/compiler.go b/rust/compiler.go index 102f9dc8d..8d2f09c2b 100644 --- a/rust/compiler.go +++ b/rust/compiler.go @@ -240,11 +240,18 @@ func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps { return deps } -func bionicDeps(deps Deps) Deps { - deps.SharedLibs = append(deps.SharedLibs, "liblog") - deps.SharedLibs = append(deps.SharedLibs, "libc") - deps.SharedLibs = append(deps.SharedLibs, "libm") - deps.SharedLibs = append(deps.SharedLibs, "libdl") +func bionicDeps(deps Deps, static bool) Deps { + bionicLibs := []string{} + bionicLibs = append(bionicLibs, "liblog") + bionicLibs = append(bionicLibs, "libc") + bionicLibs = append(bionicLibs, "libm") + bionicLibs = append(bionicLibs, "libdl") + + if static { + deps.StaticLibs = append(deps.StaticLibs, bionicLibs...) + } else { + deps.SharedLibs = append(deps.SharedLibs, bionicLibs...) + } //TODO(b/141331117) libstd requires libgcc on Android deps.StaticLibs = append(deps.StaticLibs, "libgcc") diff --git a/rust/library.go b/rust/library.go index 7a77706a9..3bba089e6 100644 --- a/rust/library.go +++ b/rust/library.go @@ -396,7 +396,7 @@ func (library *libraryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps { deps = library.baseCompiler.compilerDeps(ctx, deps) if ctx.toolchain().Bionic() && (library.dylib() || library.shared()) { - deps = bionicDeps(deps) + deps = bionicDeps(deps, false) deps.CrtBegin = "crtbegin_so" deps.CrtEnd = "crtend_so" }