diff --git a/rust/binary.go b/rust/binary.go index 1a82c9208..f75018626 100644 --- a/rust/binary.go +++ b/rust/binary.go @@ -24,9 +24,6 @@ func init() { } type BinaryCompilerProperties struct { - // passes -C prefer-dynamic to rustc, which tells it to dynamically link the stdlib - // (assuming it has no dylib dependencies already) - Prefer_dynamic *bool } type binaryDecorator struct { @@ -60,10 +57,6 @@ func NewRustBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator return module, binary } -func (binary *binaryDecorator) preferDynamic() bool { - return Bool(binary.Properties.Prefer_dynamic) -} - func (binary *binaryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags { flags = binary.baseCompiler.compilerFlags(ctx, flags) @@ -76,9 +69,6 @@ func (binary *binaryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Fla "-Wl,--no-undefined-version") } - if binary.preferDynamic() { - flags.RustFlags = append(flags.RustFlags, "-C prefer-dynamic") - } return flags } @@ -132,8 +122,9 @@ func (binary *binaryDecorator) coverageOutputZipPath() android.OptionalPath { return binary.coverageOutputZipFile } -func (binary *binaryDecorator) autoDep() autoDep { - if binary.preferDynamic() { +func (binary *binaryDecorator) autoDep(ctx BaseModuleContext) autoDep { + // Binaries default to dylib dependencies for device, rlib for host. + if ctx.Device() { return dylibAutoDep } else { return rlibAutoDep diff --git a/rust/binary_test.go b/rust/binary_test.go index b9c8698b9..5c9bd6530 100644 --- a/rust/binary_test.go +++ b/rust/binary_test.go @@ -17,44 +17,64 @@ package rust import ( "strings" "testing" + + "android/soong/android" ) -// Test that the prefer_dynamic property is handled correctly. -func TestPreferDynamicBinary(t *testing.T) { +// Test that rustlibs default linkage is correct for binaries. +func TestBinaryLinkage(t *testing.T) { + ctx := testRust(t, ` + rust_binary { + name: "fizz-buzz", + srcs: ["foo.rs"], + rustlibs: ["libfoo"], + host_supported: true, + } + rust_library { + name: "libfoo", + srcs: ["foo.rs"], + crate_name: "foo", + host_supported: true, + }`) + + fizzBuzzHost := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module) + fizzBuzzDevice := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Module().(*Module) + + if !android.InList("libfoo", fizzBuzzHost.Properties.AndroidMkRlibs) { + t.Errorf("rustlibs dependency libfoo should be an rlib dep for host modules") + } + + if !android.InList("libfoo", fizzBuzzDevice.Properties.AndroidMkDylibs) { + t.Errorf("rustlibs dependency libfoo should be an dylib dep for device modules") + } +} + +// Test that the path returned by HostToolPath is correct +func TestHostToolPath(t *testing.T) { ctx := testRust(t, ` rust_binary_host { - name: "fizz-buzz-dynamic", + name: "fizz-buzz", srcs: ["foo.rs"], - prefer_dynamic: true, - } + }`) + path := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module).HostToolPath() + if g, w := path.String(), "/host/linux-x86/bin/fizz-buzz"; !strings.Contains(g, w) { + t.Errorf("wrong host tool path, expected %q got %q", w, g) + } +} + +// Test that the flags being passed to rust_binary modules are as expected +func TestBinaryFlags(t *testing.T) { + ctx := testRust(t, ` rust_binary_host { name: "fizz-buzz", srcs: ["foo.rs"], }`) fizzBuzz := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Output("fizz-buzz") - fizzBuzzDynamic := ctx.ModuleForTests("fizz-buzz-dynamic", "linux_glibc_x86_64").Output("fizz-buzz-dynamic") - path := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module).HostToolPath() - if g, w := path.String(), "/host/linux-x86/bin/fizz-buzz"; !strings.Contains(g, w) { - t.Errorf("wrong host tool path, expected %q got %q", w, g) - } - - // Do not compile binary modules with the --test flag. - flags := fizzBuzzDynamic.Args["rustcFlags"] + flags := fizzBuzz.Args["rustcFlags"] if strings.Contains(flags, "--test") { t.Errorf("extra --test flag, rustcFlags: %#v", flags) } - if !strings.Contains(flags, "prefer-dynamic") { - t.Errorf("missing prefer-dynamic flag, rustcFlags: %#v", flags) - } - - flags = fizzBuzz.Args["rustcFlags"] - if strings.Contains(flags, "--test") { - t.Errorf("extra --test flag, rustcFlags: %#v", flags) - } - if strings.Contains(flags, "prefer-dynamic") { - t.Errorf("unexpected prefer-dynamic flag, rustcFlags: %#v", flags) - } } diff --git a/rust/compiler.go b/rust/compiler.go index ef7fb8cfc..2600f4d0f 100644 --- a/rust/compiler.go +++ b/rust/compiler.go @@ -145,6 +145,10 @@ func (compiler *baseCompiler) coverageOutputZipPath() android.OptionalPath { panic("baseCompiler does not implement coverageOutputZipPath()") } +func (compiler *baseCompiler) static() bool { + return false +} + var _ compiler = (*baseCompiler)(nil) func (compiler *baseCompiler) inData() bool { @@ -216,7 +220,15 @@ func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps { stdlib = stdlib + "_" + ctx.toolchain().RustTriple() } - deps.Rustlibs = append(deps.Rustlibs, stdlib) + // For devices, we always link stdlibs in as dylibs except for ffi static libraries. + // (rustc does not support linking libstd as a dylib for ffi static libraries) + if ctx.Host() { + deps.Rustlibs = append(deps.Rustlibs, stdlib) + } else if ctx.RustModule().compiler.static() { + deps.Rlibs = append(deps.Rlibs, stdlib) + } else { + deps.Dylibs = append(deps.Dylibs, stdlib) + } } } return deps diff --git a/rust/compiler_test.go b/rust/compiler_test.go index 8b9fccc61..56a8ef8ac 100644 --- a/rust/compiler_test.go +++ b/rust/compiler_test.go @@ -177,3 +177,30 @@ func TestLints(t *testing.T) { }) } } + +// Test that devices are linking the stdlib dynamically +func TestStdDeviceLinkage(t *testing.T) { + ctx := testRust(t, ` + rust_binary { + name: "fizz", + srcs: ["foo.rs"], + } + rust_library { + name: "libfoo", + srcs: ["foo.rs"], + crate_name: "foo", + }`) + fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Module().(*Module) + fooRlib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib").Module().(*Module) + fooDylib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").Module().(*Module) + + if !android.InList("libstd", fizz.Properties.AndroidMkDylibs) { + t.Errorf("libstd is not linked dynamically for device binaries") + } + if !android.InList("libstd", fooRlib.Properties.AndroidMkDylibs) { + t.Errorf("libstd is not linked dynamically for rlibs") + } + if !android.InList("libstd", fooDylib.Properties.AndroidMkDylibs) { + t.Errorf("libstd is not linked dynamically for dylibs") + } +} diff --git a/rust/library.go b/rust/library.go index 6766d618b..91fbe0fda 100644 --- a/rust/library.go +++ b/rust/library.go @@ -176,13 +176,13 @@ func (library *libraryDecorator) setStatic() { library.MutatedProperties.VariantIsDylib = false } -func (library *libraryDecorator) autoDep() autoDep { +func (library *libraryDecorator) autoDep(ctx BaseModuleContext) autoDep { if library.rlib() || library.static() { return rlibAutoDep } else if library.dylib() || library.shared() { return dylibAutoDep } else { - return rlibAutoDep + panic("autoDep called on library" + ctx.ModuleName() + "that has no enabled variants.") } } diff --git a/rust/library_test.go b/rust/library_test.go index 8a91cf10f..0fd9e32f9 100644 --- a/rust/library_test.go +++ b/rust/library_test.go @@ -144,6 +144,22 @@ func TestSharedLibrary(t *testing.T) { } } +func TestStaticLibraryLinkage(t *testing.T) { + ctx := testRust(t, ` + rust_ffi_static { + name: "libfoo", + srcs: ["foo.rs"], + crate_name: "foo", + }`) + + libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static") + + if !android.InList("libstd", libfoo.Module().(*Module).Properties.AndroidMkRlibs) { + t.Errorf("Static libstd rlib expected to be a dependency of Rust static libraries. Rlib deps are: %#v", + libfoo.Module().(*Module).Properties.AndroidMkDylibs) + } +} + // Test that variants pull in the right type of rustlib autodep func TestAutoDeps(t *testing.T) { diff --git a/rust/proc_macro.go b/rust/proc_macro.go index 3dd2521a3..748879cc8 100644 --- a/rust/proc_macro.go +++ b/rust/proc_macro.go @@ -80,6 +80,6 @@ func (procMacro *procMacroDecorator) getStem(ctx ModuleContext) string { return stem + String(procMacro.baseCompiler.Properties.Suffix) } -func (procMacro *procMacroDecorator) autoDep() autoDep { +func (procMacro *procMacroDecorator) autoDep(ctx BaseModuleContext) autoDep { return rlibAutoDep } diff --git a/rust/rust.go b/rust/rust.go index b69786976..80fe62243 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -289,6 +289,8 @@ type compiler interface { Disabled() bool SetDisabled() + + static() bool } type exportedFlagsProducer interface { @@ -740,7 +742,7 @@ var ( ) type autoDeppable interface { - autoDep() autoDep + autoDep(ctx BaseModuleContext) autoDep } func (mod *Module) begin(ctx BaseModuleContext) { @@ -988,8 +990,8 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) { {Mutator: "rust_libraries", Variation: "dylib"}}...), dylibDepTag, deps.Dylibs...) - if deps.Rustlibs != nil { - autoDep := mod.compiler.(autoDeppable).autoDep() + if deps.Rustlibs != nil && !mod.compiler.Disabled() { + autoDep := mod.compiler.(autoDeppable).autoDep(ctx) actx.AddVariationDependencies( append(commonDepVariations, []blueprint.Variation{ {Mutator: "rust_libraries", Variation: autoDep.variation}}...), diff --git a/rust/test.go b/rust/test.go index 05c361e87..19802e392 100644 --- a/rust/test.go +++ b/rust/test.go @@ -114,7 +114,7 @@ func (test *testDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags { return flags } -func (test *testDecorator) autoDep() autoDep { +func (test *testDecorator) autoDep(ctx BaseModuleContext) autoDep { return rlibAutoDep }