|
4 | 4 | use std::collections::{HashMap, HashSet}; |
5 | 5 | use std::ops::Deref; |
6 | 6 | use std::path::Path; |
| 7 | +use std::process::Command; |
7 | 8 |
|
8 | 9 | use crate::error::Error; |
9 | 10 | use crate::linkers::Linker; |
10 | 11 | use crate::report::Reporter; |
| 12 | +use crate::utils::run_command; |
11 | 13 |
|
12 | 14 | static SUPPORTED_TARGETS: &[TargetSpec] = &[ |
13 | 15 | // Targets with architecture specific tuning |
@@ -127,11 +129,52 @@ fn check_target( |
127 | 129 | false => ["core", "alloc"].as_slice(), |
128 | 130 | }; |
129 | 131 | check_libraries(target, &target_dir, expected_libs)?; |
| 132 | + check_default_link_args(sysroot, target)?; |
130 | 133 |
|
131 | 134 | reporter.success(&format!("target installed correctly: {}", target.tuple)); |
132 | 135 | Ok(CheckTargetOutcome::Found) |
133 | 136 | } |
134 | 137 |
|
| 138 | +/// Check if the default link args for the target are what is expected |
| 139 | +fn check_default_link_args(sysroot: &Path, target: &TargetSpec) -> Result<(), Error> { |
| 140 | + match target.linker { |
| 141 | + Linker::HostCc => (), |
| 142 | + Linker::BundledLld | Linker::CrossCc(_) => return Ok(()), // No default link args expected |
| 143 | + } |
| 144 | + |
| 145 | + let rustc = sysroot.join("bin").join("rustc"); |
| 146 | + let temp_dir = tempfile::tempdir() |
| 147 | + .map_err(|error| Error::TemporaryCompilationDirectoryCreationFailed { error })?; |
| 148 | + let temp_main = temp_dir.path().join("main.rs"); |
| 149 | + std::fs::write(&temp_main, "fn main() {}").map_err(|error| { |
| 150 | + Error::WritingSampleProgramFailed { |
| 151 | + name: "link_arg_example".into(), |
| 152 | + dest: temp_main.clone(), |
| 153 | + error, |
| 154 | + } |
| 155 | + })?; |
| 156 | + |
| 157 | + let mut command = Command::new(rustc); |
| 158 | + command.arg("--target"); |
| 159 | + command.arg(target.tuple); |
| 160 | + command.arg("--print"); |
| 161 | + command.arg("link-args"); |
| 162 | + command.arg(temp_main); |
| 163 | + let output = run_command(&mut command) |
| 164 | + .map_err(|error| Error::sample_program_compilation_failed("link-args", error))?; |
| 165 | + |
| 166 | + // All our `HostCc` targets require `-fuse-ld=lld` to be passed |
| 167 | + let fuse_ld_arg = "-fuse-ld=lld"; |
| 168 | + if !output.stdout.contains(fuse_ld_arg) { |
| 169 | + Err(Error::TargetDefaultLinkArgMissing { |
| 170 | + target: target.tuple.into(), |
| 171 | + link_arg: fuse_ld_arg.into(), |
| 172 | + }) |
| 173 | + } else { |
| 174 | + Ok(()) |
| 175 | + } |
| 176 | +} |
| 177 | + |
135 | 178 | #[derive(Debug, PartialEq, Eq)] |
136 | 179 | enum CheckTargetOutcome { |
137 | 180 | Missing, |
@@ -210,13 +253,48 @@ mod tests { |
210 | 253 | .lib("other", "0123456789abcdef") // Unknown libraries are ignored |
211 | 254 | .create(); |
212 | 255 |
|
| 256 | + let _bin = utils |
| 257 | + .bin("rustc") |
| 258 | + .expected_args(&["--target", tuple, "--print", "link-args"]) |
| 259 | + .expected_args_strict(false) |
| 260 | + .stdout("-fuse-ld=lld") |
| 261 | + .create(); |
| 262 | + |
213 | 263 | assert_eq!( |
214 | 264 | CheckTargetOutcome::Found, |
215 | 265 | check_target(utils.reporter(), utils.sysroot(), &target).unwrap() |
216 | 266 | ); |
217 | 267 | utils.assert_report_success("target installed correctly: x86_64-unknown-linux-gnu"); |
218 | 268 | } |
219 | 269 |
|
| 270 | + #[cfg(all(target_os = "linux", target_arch = "x86_64"))] // Only on x86_64 Linux since the test is specific to that. |
| 271 | + #[test] |
| 272 | + #[should_panic] |
| 273 | + fn test_check_target_std_fails_if_lld_not_used() { |
| 274 | + let tuple = "x86_64-unknown-linux-gnu"; |
| 275 | + let target = TargetSpec { tuple, std: true, linker: Linker::HostCc }; |
| 276 | + |
| 277 | + let utils = TestUtils::new(); |
| 278 | + utils |
| 279 | + .target(tuple) |
| 280 | + .lib("core", "0123456789abcdef") |
| 281 | + .lib("alloc", "0123456789abcdef") |
| 282 | + .lib("std", "0123456789abcdef") |
| 283 | + .lib("test", "0123456789abcdef") |
| 284 | + .lib("proc_macro", "0123456789abcdef") |
| 285 | + .lib("other", "0123456789abcdef") // Unknown libraries are ignored |
| 286 | + .create(); |
| 287 | + |
| 288 | + let _bin = utils |
| 289 | + .bin("rustc") |
| 290 | + .expected_args(&["--target", tuple, "--print", "link-args"]) |
| 291 | + .expected_args_strict(false) |
| 292 | + .stdout("-fuse-ld=not-lld-this-should-fail") |
| 293 | + .create(); |
| 294 | + |
| 295 | + check_target(utils.reporter(), utils.sysroot(), &target).unwrap(); // Panic! |
| 296 | + } |
| 297 | + |
220 | 298 | #[test] |
221 | 299 | fn test_check_target_no_std() { |
222 | 300 | let tuple = "x86_64-unknown-none"; |
@@ -362,4 +440,29 @@ mod tests { |
362 | 440 | assert_fail("libcore-0123456789abcdef.so"); // Different extension |
363 | 441 | assert_fail("libcore-0123456789abcdef"); // No extension |
364 | 442 | } |
| 443 | + |
| 444 | + fn check_target_default_link_args(tuple: &'static str) -> Result<(), Error> { |
| 445 | + let target = TargetSpec { tuple, std: true, linker: Linker::HostCc }; |
| 446 | + |
| 447 | + let utils = TestUtils::new(); |
| 448 | + let _bin = utils |
| 449 | + .bin("rustc") |
| 450 | + .expected_args(&["--target", tuple, "--print", "link-args"]) |
| 451 | + .expected_args_strict(false) |
| 452 | + .stdout("-fuse-ld=lld") |
| 453 | + .create(); |
| 454 | + check_default_link_args(utils.sysroot(), &target) |
| 455 | + } |
| 456 | + |
| 457 | + #[cfg(all(target_os = "linux", target_arch = "x86_64"))] |
| 458 | + #[test] |
| 459 | + fn test_check_target_default_link_args_x86_64() -> Result<(), Error> { |
| 460 | + check_target_default_link_args("x86_64-unknown-linux-gnu") |
| 461 | + } |
| 462 | + |
| 463 | + #[cfg(all(target_os = "linux", target_arch = "aarch64"))] |
| 464 | + #[test] |
| 465 | + fn test_check_target_default_link_args_x86_64() -> Result<(), Error> { |
| 466 | + check_target_default_link_args("aarch64-unknown-linux-gnu") |
| 467 | + } |
365 | 468 | } |
0 commit comments