1// Copyright 2019 The Android Open Source Project 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package rust 16 17import ( 18 "strings" 19 "testing" 20 21 "android/soong/android" 22) 23 24// Test that rustlibs default linkage is always rlib for host binaries. 25func TestBinaryHostLinkage(t *testing.T) { 26 ctx := testRust(t, ` 27 rust_binary_host { 28 name: "fizz-buzz", 29 srcs: ["foo.rs"], 30 rustlibs: ["libfoo"], 31 } 32 rust_library { 33 name: "libfoo", 34 srcs: ["foo.rs"], 35 crate_name: "foo", 36 host_supported: true, 37 } 38 `) 39 fizzBuzz := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module) 40 if !android.InList("libfoo.rlib-std", fizzBuzz.Properties.AndroidMkRlibs) { 41 t.Errorf("rustlibs dependency libfoo should be an rlib dep for host binaries") 42 } 43} 44 45// Test that rustlibs default linkage is correct for binaries. 46func TestBinaryLinkage(t *testing.T) { 47 ctx := testRust(t, ` 48 rust_binary { 49 name: "fizz-buzz", 50 srcs: ["foo.rs"], 51 rustlibs: ["libfoo"], 52 host_supported: true, 53 } 54 rust_binary { 55 name: "rlib_linked", 56 srcs: ["foo.rs"], 57 rustlibs: ["libfoo"], 58 host_supported: true, 59 prefer_rlib: true, 60 } 61 rust_library { 62 name: "libfoo", 63 srcs: ["foo.rs"], 64 crate_name: "foo", 65 host_supported: true, 66 }`) 67 68 fizzBuzzHost := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module) 69 fizzBuzzDevice := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Module().(*Module) 70 71 if !android.InList("libfoo.rlib-std", fizzBuzzHost.Properties.AndroidMkRlibs) { 72 t.Errorf("rustlibs dependency libfoo should be an rlib dep for host modules") 73 } 74 75 if !android.InList("libfoo", fizzBuzzDevice.Properties.AndroidMkDylibs) { 76 t.Errorf("rustlibs dependency libfoo should be an dylib dep for device modules") 77 } 78 79 rlibLinkDevice := ctx.ModuleForTests("rlib_linked", "android_arm64_armv8-a").Module().(*Module) 80 81 if !android.InList("libfoo.rlib-std", rlibLinkDevice.Properties.AndroidMkRlibs) { 82 t.Errorf("rustlibs dependency libfoo should be an rlib dep for device modules when prefer_rlib is set") 83 } 84} 85 86// Test that prefer_rlib links in libstd statically as well as rustlibs. 87func TestBinaryPreferRlib(t *testing.T) { 88 ctx := testRust(t, ` 89 rust_binary { 90 name: "rlib_linked", 91 srcs: ["foo.rs"], 92 rustlibs: ["libfoo"], 93 host_supported: true, 94 prefer_rlib: true, 95 } 96 rust_library { 97 name: "libfoo", 98 srcs: ["foo.rs"], 99 crate_name: "foo", 100 host_supported: true, 101 }`) 102 103 mod := ctx.ModuleForTests("rlib_linked", "android_arm64_armv8-a").Module().(*Module) 104 105 if !android.InList("libfoo.rlib-std", mod.Properties.AndroidMkRlibs) { 106 t.Errorf("rustlibs dependency libfoo should be an rlib dep when prefer_rlib is defined") 107 } 108 109 if !android.InList("libstd", mod.Properties.AndroidMkRlibs) { 110 t.Errorf("libstd dependency should be an rlib dep when prefer_rlib is defined") 111 } 112} 113 114// Test that the path returned by HostToolPath is correct 115func TestHostToolPath(t *testing.T) { 116 ctx := testRust(t, ` 117 rust_binary_host { 118 name: "fizz-buzz", 119 srcs: ["foo.rs"], 120 }`) 121 122 path := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module).HostToolPath() 123 if g, w := path.String(), "/host/linux-x86/bin/fizz-buzz"; !strings.Contains(g, w) { 124 t.Errorf("wrong host tool path, expected %q got %q", w, g) 125 } 126} 127 128// Test that the flags being passed to rust_binary modules are as expected 129func TestBinaryFlags(t *testing.T) { 130 ctx := testRust(t, ` 131 rust_binary_host { 132 name: "fizz-buzz", 133 srcs: ["foo.rs"], 134 }`) 135 136 fizzBuzz := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Rule("rustc") 137 138 flags := fizzBuzz.Args["rustcFlags"] 139 if strings.Contains(flags, "--test") { 140 t.Errorf("extra --test flag, rustcFlags: %#v", flags) 141 } 142} 143 144// Test that the bootstrap property sets the appropriate linker 145func TestBootstrap(t *testing.T) { 146 ctx := testRust(t, ` 147 rust_binary { 148 name: "foo", 149 srcs: ["foo.rs"], 150 bootstrap: true, 151 }`) 152 153 foo := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Rule("rustc") 154 155 flag := "-Wl,-dynamic-linker,/system/bin/bootstrap/linker64" 156 if !strings.Contains(foo.Args["linkFlags"], flag) { 157 t.Errorf("missing link flag to use bootstrap linker, expecting %#v, linkFlags: %#v", flag, foo.Args["linkFlags"]) 158 } 159} 160 161func TestStaticBinaryFlags(t *testing.T) { 162 ctx := testRust(t, ` 163 rust_binary { 164 name: "fizz", 165 srcs: ["foo.rs"], 166 static_executable: true, 167 }`) 168 169 fizzOut := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Rule("rustc") 170 fizzMod := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Module().(*Module) 171 172 flags := fizzOut.Args["rustcFlags"] 173 linkFlags := fizzOut.Args["linkFlags"] 174 if !strings.Contains(flags, "-C relocation-model=static") { 175 t.Errorf("static binary missing '-C relocation-model=static' in rustcFlags, found: %#v", flags) 176 } 177 if !strings.Contains(flags, "-C panic=abort") { 178 t.Errorf("static binary missing '-C panic=abort' in rustcFlags, found: %#v", flags) 179 } 180 if !strings.Contains(linkFlags, "-static") { 181 t.Errorf("static binary missing '-static' in linkFlags, found: %#v", flags) 182 } 183 184 if !android.InList("libc", fizzMod.Properties.AndroidMkStaticLibs) { 185 t.Errorf("static binary not linking against libc as a static library") 186 } 187 if len(fizzMod.transitiveAndroidMkSharedLibs.ToList()) > 0 { 188 t.Errorf("static binary incorrectly linking against shared libraries") 189 } 190} 191 192func TestLinkObjects(t *testing.T) { 193 ctx := testRust(t, ` 194 rust_binary { 195 name: "fizz-buzz", 196 srcs: ["foo.rs"], 197 shared_libs: ["libfoo"], 198 } 199 cc_library { 200 name: "libfoo", 201 }`) 202 203 fizzBuzz := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Rule("rustc") 204 linkFlags := fizzBuzz.Args["linkFlags"] 205 if !strings.Contains(linkFlags, "/libfoo.so") { 206 t.Errorf("missing shared dependency 'libfoo.so' in linkFlags: %#v", linkFlags) 207 } 208} 209 210// Test that stripped versions are correctly generated and used. 211func TestStrippedBinary(t *testing.T) { 212 ctx := testRust(t, ` 213 rust_binary { 214 name: "foo", 215 srcs: ["foo.rs"], 216 } 217 rust_binary { 218 name: "bar", 219 srcs: ["foo.rs"], 220 strip: { 221 none: true 222 } 223 } 224 `) 225 226 foo := ctx.ModuleForTests("foo", "android_arm64_armv8-a") 227 foo.Output("unstripped/foo") 228 foo.Output("foo") 229 230 // Check that the `cp` rules is using the stripped version as input. 231 cp := foo.Rule("android.Cp") 232 if strings.HasSuffix(cp.Input.String(), "unstripped/foo") { 233 t.Errorf("installed binary not based on stripped version: %v", cp.Input) 234 } 235 236 fizzBar := ctx.ModuleForTests("bar", "android_arm64_armv8-a").MaybeOutput("unstripped/bar") 237 if fizzBar.Rule != nil { 238 t.Errorf("unstripped binary exists, so stripped binary has incorrectly been generated") 239 } 240} 241