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 variants are being generated correctly, and that crate-types are correct. 25func TestLibraryVariants(t *testing.T) { 26 27 ctx := testRust(t, ` 28 rust_library_host { 29 name: "libfoo", 30 srcs: ["foo.rs"], 31 crate_name: "foo", 32 } 33 rust_ffi_host { 34 name: "libfoo.ffi", 35 srcs: ["foo.rs"], 36 crate_name: "foo" 37 }`) 38 39 // Test all variants are being built. 40 libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib_rlib-std").Output("libfoo.rlib") 41 libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Output("libfoo.dylib.so") 42 libfooStatic := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_static").Output("libfoo.ffi.a") 43 libfooShared := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_shared").Output("libfoo.ffi.so") 44 45 rlibCrateType := "rlib" 46 dylibCrateType := "dylib" 47 sharedCrateType := "cdylib" 48 staticCrateType := "static" 49 50 // Test crate type for rlib is correct. 51 if !strings.Contains(libfooRlib.Args["rustcFlags"], "crate-type="+rlibCrateType) { 52 t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", rlibCrateType, libfooRlib.Args["rustcFlags"]) 53 } 54 55 // Test crate type for dylib is correct. 56 if !strings.Contains(libfooDylib.Args["rustcFlags"], "crate-type="+dylibCrateType) { 57 t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", dylibCrateType, libfooDylib.Args["rustcFlags"]) 58 } 59 60 // Test crate type for C static libraries is correct. 61 if !strings.Contains(libfooStatic.Args["rustcFlags"], "crate-type="+staticCrateType) { 62 t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", staticCrateType, libfooStatic.Args["rustcFlags"]) 63 } 64 65 // Test crate type for C shared libraries is correct. 66 if !strings.Contains(libfooShared.Args["rustcFlags"], "crate-type="+sharedCrateType) { 67 t.Errorf("missing crate-type for shared variant, expecting %#v, got rustcFlags: %#v", sharedCrateType, libfooShared.Args["rustcFlags"]) 68 } 69 70} 71 72// Test that dylibs are not statically linking the standard library. 73func TestDylibPreferDynamic(t *testing.T) { 74 ctx := testRust(t, ` 75 rust_library_host_dylib { 76 name: "libfoo", 77 srcs: ["foo.rs"], 78 crate_name: "foo", 79 }`) 80 81 libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Output("libfoo.dylib.so") 82 83 if !strings.Contains(libfooDylib.Args["rustcFlags"], "prefer-dynamic") { 84 t.Errorf("missing prefer-dynamic flag for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"]) 85 } 86} 87 88func TestValidateLibraryStem(t *testing.T) { 89 testRustError(t, "crate_name must be defined.", ` 90 rust_library_host { 91 name: "libfoo", 92 srcs: ["foo.rs"], 93 }`) 94 95 testRustError(t, "library crate_names must be alphanumeric with underscores allowed", ` 96 rust_library_host { 97 name: "libfoo-bar", 98 srcs: ["foo.rs"], 99 crate_name: "foo-bar" 100 }`) 101 102 testRustError(t, "Invalid name or stem property; library filenames must start with lib<crate_name>", ` 103 rust_library_host { 104 name: "foobar", 105 srcs: ["foo.rs"], 106 crate_name: "foo_bar" 107 }`) 108 testRustError(t, "Invalid name or stem property; library filenames must start with lib<crate_name>", ` 109 rust_library_host { 110 name: "foobar", 111 stem: "libfoo", 112 srcs: ["foo.rs"], 113 crate_name: "foo_bar" 114 }`) 115 testRustError(t, "Invalid name or stem property; library filenames must start with lib<crate_name>", ` 116 rust_library_host { 117 name: "foobar", 118 stem: "foo_bar", 119 srcs: ["foo.rs"], 120 crate_name: "foo_bar" 121 }`) 122 123} 124 125func TestSharedLibrary(t *testing.T) { 126 ctx := testRust(t, ` 127 rust_ffi_shared { 128 name: "libfoo", 129 srcs: ["foo.rs"], 130 crate_name: "foo", 131 }`) 132 133 libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared") 134 135 libfooOutput := libfoo.Output("libfoo.so") 136 if !strings.Contains(libfooOutput.Args["linkFlags"], "-Wl,-soname=libfoo.so") { 137 t.Errorf("missing expected -Wl,-soname linker flag for libfoo shared lib, linkFlags: %#v", 138 libfooOutput.Args["linkFlags"]) 139 } 140 141 if !android.InList("libstd", libfoo.Module().(*Module).Properties.AndroidMkDylibs) { 142 t.Errorf("Non-static libstd dylib expected to be a dependency of Rust shared libraries. Dylib deps are: %#v", 143 libfoo.Module().(*Module).Properties.AndroidMkDylibs) 144 } 145} 146 147func TestStaticLibraryLinkage(t *testing.T) { 148 ctx := testRust(t, ` 149 rust_ffi_static { 150 name: "libfoo", 151 srcs: ["foo.rs"], 152 crate_name: "foo", 153 }`) 154 155 libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static") 156 157 if !android.InList("libstd", libfoo.Module().(*Module).Properties.AndroidMkRlibs) { 158 t.Errorf("Static libstd rlib expected to be a dependency of Rust static libraries. Rlib deps are: %#v", 159 libfoo.Module().(*Module).Properties.AndroidMkDylibs) 160 } 161} 162 163// Test that variants pull in the right type of rustlib autodep 164func TestAutoDeps(t *testing.T) { 165 166 ctx := testRust(t, ` 167 rust_library_host { 168 name: "libbar", 169 srcs: ["bar.rs"], 170 crate_name: "bar", 171 } 172 rust_library_host { 173 name: "libfoo", 174 srcs: ["foo.rs"], 175 crate_name: "foo", 176 rustlibs: ["libbar"], 177 } 178 rust_ffi_host { 179 name: "libfoo.ffi", 180 srcs: ["foo.rs"], 181 crate_name: "foo", 182 rustlibs: ["libbar"], 183 }`) 184 185 libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib_rlib-std") 186 libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib") 187 libfooStatic := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_static") 188 libfooShared := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_shared") 189 190 for _, static := range []android.TestingModule{libfooRlib, libfooStatic} { 191 if !android.InList("libbar.rlib-std", static.Module().(*Module).Properties.AndroidMkRlibs) { 192 t.Errorf("libbar not present as rlib dependency in static lib") 193 } 194 if android.InList("libbar", static.Module().(*Module).Properties.AndroidMkDylibs) { 195 t.Errorf("libbar present as dynamic dependency in static lib") 196 } 197 } 198 199 for _, dyn := range []android.TestingModule{libfooDylib, libfooShared} { 200 if !android.InList("libbar", dyn.Module().(*Module).Properties.AndroidMkDylibs) { 201 t.Errorf("libbar not present as dynamic dependency in dynamic lib") 202 } 203 if android.InList("libbar.dylib-std", dyn.Module().(*Module).Properties.AndroidMkRlibs) { 204 t.Errorf("libbar present as rlib dependency in dynamic lib") 205 } 206 207 } 208} 209 210// Test that stripped versions are correctly generated and used. 211func TestStrippedLibrary(t *testing.T) { 212 ctx := testRust(t, ` 213 rust_library_dylib { 214 name: "libfoo", 215 crate_name: "foo", 216 srcs: ["foo.rs"], 217 } 218 rust_library_dylib { 219 name: "libbar", 220 crate_name: "bar", 221 srcs: ["foo.rs"], 222 strip: { 223 none: true 224 } 225 } 226 `) 227 228 foo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib") 229 foo.Output("stripped/libfoo.dylib.so") 230 // Check that the `cp` rule is using the stripped version as input. 231 cp := foo.Rule("android.Cp") 232 if !strings.HasSuffix(cp.Input.String(), "stripped/libfoo.dylib.so") { 233 t.Errorf("installed binary not based on stripped version: %v", cp.Input) 234 } 235 236 fizzBar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_dylib").MaybeOutput("stripped/libbar.dylib.so") 237 if fizzBar.Rule != nil { 238 t.Errorf("stripped version of bar has been generated") 239 } 240} 241 242func TestLibstdLinkage(t *testing.T) { 243 ctx := testRust(t, ` 244 rust_library { 245 name: "libfoo", 246 srcs: ["foo.rs"], 247 crate_name: "foo", 248 } 249 rust_ffi { 250 name: "libbar", 251 srcs: ["foo.rs"], 252 crate_name: "bar", 253 rustlibs: ["libfoo"], 254 } 255 rust_ffi { 256 name: "libbar.prefer_rlib", 257 srcs: ["foo.rs"], 258 crate_name: "bar", 259 rustlibs: ["libfoo"], 260 prefer_rlib: true, 261 }`) 262 263 libfooDylib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").Module().(*Module) 264 libfooRlibStatic := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_rlib-std").Module().(*Module) 265 libfooRlibDynamic := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_dylib-std").Module().(*Module) 266 267 libbarShared := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module().(*Module) 268 libbarStatic := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_static").Module().(*Module) 269 270 // prefer_rlib works the same for both rust_library and rust_ffi, so a single check is sufficient here. 271 libbarRlibStd := ctx.ModuleForTests("libbar.prefer_rlib", "android_arm64_armv8-a_shared").Module().(*Module) 272 273 if !android.InList("libstd", libfooRlibStatic.Properties.AndroidMkRlibs) { 274 t.Errorf("rlib-std variant for device rust_library_rlib does not link libstd as an rlib") 275 } 276 if !android.InList("libstd", libfooRlibDynamic.Properties.AndroidMkDylibs) { 277 t.Errorf("dylib-std variant for device rust_library_rlib does not link libstd as an dylib") 278 } 279 if !android.InList("libstd", libfooDylib.Properties.AndroidMkDylibs) { 280 t.Errorf("Device rust_library_dylib does not link libstd as an dylib") 281 } 282 283 if !android.InList("libstd", libbarShared.Properties.AndroidMkDylibs) { 284 t.Errorf("Device rust_ffi_shared does not link libstd as an dylib") 285 } 286 if !android.InList("libstd", libbarStatic.Properties.AndroidMkRlibs) { 287 t.Errorf("Device rust_ffi_static does not link libstd as an rlib") 288 } 289 if !android.InList("libfoo.rlib-std", libbarStatic.Properties.AndroidMkRlibs) { 290 t.Errorf("Device rust_ffi_static does not link dependent rustlib rlib-std variant") 291 } 292 if !android.InList("libstd", libbarRlibStd.Properties.AndroidMkRlibs) { 293 t.Errorf("rust_ffi with prefer_rlib does not link libstd as an rlib") 294 } 295 296} 297