rust: Add static binary support
Adds the "static_executable" property to rust_binary modules which
allows for building fully static executables. This only impacts bionic
targets.
Bug: 169434439
Test: rust_binary module with static_executable true builds, runs on
device.
Change-Id: I83c19fddd070859b7e56d248237cfd73e1768519
diff --git a/rust/binary.go b/rust/binary.go
index 2758ae0..af39d38 100644
--- a/rust/binary.go
+++ b/rust/binary.go
@@ -28,6 +28,12 @@
// 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 @@
"-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 @@
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 @@
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) 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) 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 f31a7fc..b44a5bc 100644
--- a/rust/binary_test.go
+++ b/rust/binary_test.go
@@ -114,6 +114,34 @@
}
}
+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 d8d126d..e5112de 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -267,7 +267,7 @@
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 102f9dc..8d2f09c 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -240,11 +240,18 @@
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 7a77706..3bba089 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -396,7 +396,7 @@
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"
}