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 feature flags are being correctly generated. 25func TestFeaturesToFlags(t *testing.T) { 26 ctx := testRust(t, ` 27 rust_library_host_dylib { 28 name: "libfoo", 29 srcs: ["foo.rs"], 30 crate_name: "foo", 31 features: [ 32 "fizz", 33 "buzz" 34 ], 35 }`) 36 37 libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc") 38 39 if !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'feature=\"fizz\"'") || 40 !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'feature=\"buzz\"'") { 41 t.Fatalf("missing fizz and buzz feature flags for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"]) 42 } 43} 44 45// Test that cfgs flags are being correctly generated. 46func TestCfgsToFlags(t *testing.T) { 47 ctx := testRust(t, ` 48 rust_library_host { 49 name: "libfoo", 50 srcs: ["foo.rs"], 51 crate_name: "foo", 52 cfgs: [ 53 "std", 54 "cfg1=\"one\"" 55 ], 56 }`) 57 58 libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc") 59 60 if !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'std'") || 61 !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'cfg1=\"one\"'") { 62 t.Fatalf("missing std and cfg1 flags for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"]) 63 } 64} 65 66func TestLtoFlag(t *testing.T) { 67 ctx := testRust(t, ` 68 rust_library_host { 69 name: "libfoo", 70 srcs: ["foo.rs"], 71 crate_name: "foo", 72 lto: { 73 thin: false, 74 } 75 } 76 77 rust_library_host { 78 name: "libfoo_lto", 79 srcs: ["foo.rs"], 80 crate_name: "foo", 81 } 82 `) 83 84 libfoo := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc") 85 libfooLto := ctx.ModuleForTests("libfoo_lto", "linux_glibc_x86_64_dylib").Rule("rustc") 86 87 if strings.Contains(libfoo.Args["rustcFlags"], "-C lto=thin") { 88 t.Fatalf("libfoo expected to disable lto -- rustcFlags: %#v", libfoo.Args["rustcFlags"]) 89 } 90 if !strings.Contains(libfooLto.Args["rustcFlags"], "-C lto=thin") { 91 t.Fatalf("libfoo expected to enable lto by default -- rustcFlags: %#v", libfooLto.Args["rustcFlags"]) 92 } 93} 94 95// Test that we reject multiple source files. 96func TestEnforceSingleSourceFile(t *testing.T) { 97 98 singleSrcError := "srcs can only contain one path for a rust file and source providers prefixed by \":\"" 99 prebuiltSingleSrcError := "prebuilt libraries can only have one entry in srcs" 100 101 // Test libraries 102 testRustError(t, singleSrcError, ` 103 rust_library_host { 104 name: "foo-bar-library", 105 srcs: ["foo.rs", "src/bar.rs"], 106 }`) 107 108 // Test binaries 109 testRustError(t, singleSrcError, ` 110 rust_binary_host { 111 name: "foo-bar-binary", 112 srcs: ["foo.rs", "src/bar.rs"], 113 }`) 114 115 // Test proc_macros 116 testRustError(t, singleSrcError, ` 117 rust_proc_macro { 118 name: "foo-bar-proc-macro", 119 srcs: ["foo.rs", "src/bar.rs"], 120 }`) 121 122 // Test prebuilts 123 testRustError(t, prebuiltSingleSrcError, ` 124 rust_prebuilt_dylib { 125 name: "foo-bar-prebuilt", 126 srcs: ["liby.so", "libz.so"], 127 host_supported: true, 128 }`) 129} 130 131// Test that we reject _no_ source files. 132func TestEnforceMissingSourceFiles(t *testing.T) { 133 134 singleSrcError := "srcs must not be empty" 135 136 // Test libraries 137 testRustError(t, singleSrcError, ` 138 rust_library_host { 139 name: "foo-bar-library", 140 crate_name: "foo", 141 }`) 142 143 // Test binaries 144 testRustError(t, singleSrcError, ` 145 rust_binary_host { 146 name: "foo-bar-binary", 147 crate_name: "foo", 148 }`) 149 150 // Test proc_macros 151 testRustError(t, singleSrcError, ` 152 rust_proc_macro { 153 name: "foo-bar-proc-macro", 154 crate_name: "foo", 155 }`) 156 157 // Test prebuilts 158 testRustError(t, singleSrcError, ` 159 rust_prebuilt_dylib { 160 name: "foo-bar-prebuilt", 161 crate_name: "foo", 162 host_supported: true, 163 }`) 164} 165 166// Test environment vars for Cargo compat are set. 167func TestCargoCompat(t *testing.T) { 168 ctx := testRust(t, ` 169 rust_binary { 170 name: "fizz", 171 srcs: ["foo.rs"], 172 crate_name: "foo", 173 cargo_env_compat: true, 174 cargo_pkg_version: "1.0.0" 175 }`) 176 177 fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Rule("rustc") 178 179 if !strings.Contains(fizz.Args["envVars"], "CARGO_BIN_NAME=fizz") { 180 t.Fatalf("expected 'CARGO_BIN_NAME=fizz' in envVars, actual envVars: %#v", fizz.Args["envVars"]) 181 } 182 if !strings.Contains(fizz.Args["envVars"], "CARGO_CRATE_NAME=foo") { 183 t.Fatalf("expected 'CARGO_CRATE_NAME=foo' in envVars, actual envVars: %#v", fizz.Args["envVars"]) 184 } 185 if !strings.Contains(fizz.Args["envVars"], "CARGO_PKG_VERSION=1.0.0") { 186 t.Fatalf("expected 'CARGO_PKG_VERSION=1.0.0' in envVars, actual envVars: %#v", fizz.Args["envVars"]) 187 } 188} 189 190func TestInstallDir(t *testing.T) { 191 ctx := testRust(t, ` 192 rust_library_dylib { 193 name: "libfoo", 194 srcs: ["foo.rs"], 195 crate_name: "foo", 196 } 197 rust_binary { 198 name: "fizzbuzz", 199 srcs: ["foo.rs"], 200 }`) 201 202 install_path_lib64 := ctx.ModuleForTests("libfoo", 203 "android_arm64_armv8-a_dylib").Module().(*Module).compiler.(*libraryDecorator).path.String() 204 install_path_lib32 := ctx.ModuleForTests("libfoo", 205 "android_arm_armv7-a-neon_dylib").Module().(*Module).compiler.(*libraryDecorator).path.String() 206 install_path_bin := ctx.ModuleForTests("fizzbuzz", 207 "android_arm64_armv8-a").Module().(*Module).compiler.(*binaryDecorator).path.String() 208 209 if !strings.HasSuffix(install_path_lib64, "system/lib64/libfoo.dylib.so") { 210 t.Fatalf("unexpected install path for 64-bit library: %#v", install_path_lib64) 211 } 212 if !strings.HasSuffix(install_path_lib32, "system/lib/libfoo.dylib.so") { 213 t.Fatalf("unexpected install path for 32-bit library: %#v", install_path_lib32) 214 } 215 if !strings.HasSuffix(install_path_bin, "system/bin/fizzbuzz") { 216 t.Fatalf("unexpected install path for binary: %#v", install_path_bin) 217 } 218} 219 220func TestLints(t *testing.T) { 221 222 bp := ` 223 // foo uses the default value of lints 224 rust_library { 225 name: "libfoo", 226 srcs: ["foo.rs"], 227 crate_name: "foo", 228 } 229 // bar forces the use of the "android" lint set 230 rust_library { 231 name: "libbar", 232 srcs: ["foo.rs"], 233 crate_name: "bar", 234 lints: "android", 235 } 236 // foobar explicitly disable all lints 237 rust_library { 238 name: "libfoobar", 239 srcs: ["foo.rs"], 240 crate_name: "foobar", 241 lints: "none", 242 }` 243 244 var lintTests = []struct { 245 modulePath string 246 fooFlags string 247 }{ 248 {"", "${config.RustDefaultLints}"}, 249 {"external/", "${config.RustAllowAllLints}"}, 250 {"hardware/", "${config.RustVendorLints}"}, 251 } 252 253 for _, tc := range lintTests { 254 t.Run("path="+tc.modulePath, func(t *testing.T) { 255 256 result := android.GroupFixturePreparers( 257 prepareForRustTest, 258 // Test with the blueprint file in different directories. 259 android.FixtureAddTextFile(tc.modulePath+"Android.bp", bp), 260 ).RunTest(t) 261 262 r := result.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").MaybeRule("rustc") 263 android.AssertStringDoesContain(t, "libfoo flags", r.Args["rustcFlags"], tc.fooFlags) 264 265 r = result.ModuleForTests("libbar", "android_arm64_armv8-a_dylib").MaybeRule("rustc") 266 android.AssertStringDoesContain(t, "libbar flags", r.Args["rustcFlags"], "${config.RustDefaultLints}") 267 268 r = result.ModuleForTests("libfoobar", "android_arm64_armv8-a_dylib").MaybeRule("rustc") 269 android.AssertStringDoesContain(t, "libfoobar flags", r.Args["rustcFlags"], "${config.RustAllowAllLints}") 270 }) 271 } 272} 273 274// Test that devices are linking the stdlib dynamically 275func TestStdDeviceLinkage(t *testing.T) { 276 ctx := testRust(t, ` 277 rust_binary { 278 name: "fizz", 279 srcs: ["foo.rs"], 280 } 281 rust_library { 282 name: "libfoo", 283 srcs: ["foo.rs"], 284 crate_name: "foo", 285 }`) 286 fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Module().(*Module) 287 fooRlib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_dylib-std").Module().(*Module) 288 fooDylib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").Module().(*Module) 289 290 if !android.InList("libstd", fizz.Properties.AndroidMkDylibs) { 291 t.Errorf("libstd is not linked dynamically for device binaries") 292 } 293 if !android.InList("libstd", fooRlib.Properties.AndroidMkDylibs) { 294 t.Errorf("libstd is not linked dynamically for rlibs") 295 } 296 if !android.InList("libstd", fooDylib.Properties.AndroidMkDylibs) { 297 t.Errorf("libstd is not linked dynamically for dylibs") 298 } 299} 300 301// Ensure that manual link flags are disallowed. 302func TestManualLinkageRejection(t *testing.T) { 303 // rustc flags 304 testRustError(t, ".* cannot be manually specified", ` 305 rust_binary { 306 name: "foo", 307 srcs: [ 308 "foo.rs", 309 ], 310 flags: ["-lbar"], 311 } 312 `) 313 testRustError(t, ".* cannot be manually specified", ` 314 rust_binary { 315 name: "foo", 316 srcs: [ 317 "foo.rs", 318 ], 319 flags: ["--extern=foo"], 320 } 321 `) 322 testRustError(t, ".* cannot be manually specified", ` 323 rust_binary { 324 name: "foo", 325 srcs: [ 326 "foo.rs", 327 ], 328 flags: ["-Clink-args=foo"], 329 } 330 `) 331 testRustError(t, ".* cannot be manually specified", ` 332 rust_binary { 333 name: "foo", 334 srcs: [ 335 "foo.rs", 336 ], 337 flags: ["-C link-args=foo"], 338 } 339 `) 340 testRustError(t, ".* cannot be manually specified", ` 341 rust_binary { 342 name: "foo", 343 srcs: [ 344 "foo.rs", 345 ], 346 flags: ["-L foo/"], 347 } 348 `) 349 350 // lld flags 351 testRustError(t, ".* cannot be manually specified", ` 352 rust_binary { 353 name: "foo", 354 srcs: [ 355 "foo.rs", 356 ], 357 ld_flags: ["-Wl,-L bar/"], 358 } 359 `) 360 testRustError(t, ".* cannot be manually specified", ` 361 rust_binary { 362 name: "foo", 363 srcs: [ 364 "foo.rs", 365 ], 366 ld_flags: ["-Wl,-lbar"], 367 } 368 `) 369} 370