|
1 | 1 | //! Errors emitted by codegen_ssa
|
2 | 2 |
|
3 | 3 | use std::borrow::Cow;
|
| 4 | +use std::ffi::OsString; |
4 | 5 | use std::io::Error;
|
5 | 6 | use std::num::ParseIntError;
|
6 | 7 | use std::path::{Path, PathBuf};
|
@@ -345,21 +346,82 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for ThorinErrorWrapper {
|
345 | 346 | }
|
346 | 347 |
|
347 | 348 | pub(crate) struct LinkingFailed<'a> {
|
348 |
| - pub linker_path: &'a PathBuf, |
| 349 | + pub linker_path: &'a Path, |
349 | 350 | pub exit_status: ExitStatus,
|
350 |
| - pub command: &'a Command, |
| 351 | + pub command: Command, |
351 | 352 | pub escaped_output: String,
|
| 353 | + pub verbose: bool, |
352 | 354 | }
|
353 | 355 |
|
354 | 356 | impl<G: EmissionGuarantee> Diagnostic<'_, G> for LinkingFailed<'_> {
|
355 |
| - fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { |
| 357 | + fn into_diag(mut self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { |
356 | 358 | let mut diag = Diag::new(dcx, level, fluent::codegen_ssa_linking_failed);
|
357 | 359 | diag.arg("linker_path", format!("{}", self.linker_path.display()));
|
358 | 360 | diag.arg("exit_status", format!("{}", self.exit_status));
|
359 | 361 |
|
360 | 362 | let contains_undefined_ref = self.escaped_output.contains("undefined reference to");
|
361 | 363 |
|
362 |
| - diag.note(format!("{:?}", self.command)).note(self.escaped_output); |
| 364 | + if self.verbose { |
| 365 | + diag.note(format!("{:?}", self.command)); |
| 366 | + } else { |
| 367 | + enum ArgGroup { |
| 368 | + Regular(OsString), |
| 369 | + Objects(usize), |
| 370 | + Rlibs(PathBuf, Vec<OsString>), |
| 371 | + } |
| 372 | + |
| 373 | + // Omit rust object files and fold rlibs in the error by default to make linker errors a |
| 374 | + // bit less verbose. |
| 375 | + let orig_args = self.command.take_args(); |
| 376 | + let mut args: Vec<ArgGroup> = vec![]; |
| 377 | + for arg in orig_args { |
| 378 | + if arg.as_encoded_bytes().ends_with(b".rcgu.o") { |
| 379 | + if let Some(ArgGroup::Objects(n)) = args.last_mut() { |
| 380 | + *n += 1; |
| 381 | + } else { |
| 382 | + args.push(ArgGroup::Objects(1)); |
| 383 | + } |
| 384 | + } else if arg.as_encoded_bytes().ends_with(b".rlib") { |
| 385 | + let rlib_path = Path::new(&arg); |
| 386 | + let dir = rlib_path.parent().unwrap(); |
| 387 | + let filename = rlib_path.file_name().unwrap().to_owned(); |
| 388 | + if let Some(ArgGroup::Rlibs(parent, rlibs)) = args.last_mut() { |
| 389 | + if parent == dir { |
| 390 | + rlibs.push(filename); |
| 391 | + } else { |
| 392 | + args.push(ArgGroup::Rlibs(dir.to_owned(), vec![filename])); |
| 393 | + } |
| 394 | + } else { |
| 395 | + args.push(ArgGroup::Rlibs(dir.to_owned(), vec![filename])); |
| 396 | + } |
| 397 | + } else { |
| 398 | + args.push(ArgGroup::Regular(arg)); |
| 399 | + } |
| 400 | + } |
| 401 | + self.command.args(args.into_iter().map(|arg_group| match arg_group { |
| 402 | + ArgGroup::Regular(arg) => arg, |
| 403 | + ArgGroup::Objects(n) => OsString::from(format!("<{n} object files omitted>")), |
| 404 | + ArgGroup::Rlibs(dir, rlibs) => { |
| 405 | + let mut arg = dir.into_os_string(); |
| 406 | + arg.push("/{"); |
| 407 | + let mut first = true; |
| 408 | + for rlib in rlibs { |
| 409 | + if !first { |
| 410 | + arg.push(","); |
| 411 | + } |
| 412 | + first = false; |
| 413 | + arg.push(rlib); |
| 414 | + } |
| 415 | + arg.push("}"); |
| 416 | + arg |
| 417 | + } |
| 418 | + })); |
| 419 | + |
| 420 | + diag.note(format!("{:?}", self.command)); |
| 421 | + diag.note("some arguments are omitted. use `--verbose` to show all linker arguments"); |
| 422 | + } |
| 423 | + |
| 424 | + diag.note(self.escaped_output); |
363 | 425 |
|
364 | 426 | // Trying to match an error from OS linkers
|
365 | 427 | // which by now we have no way to translate.
|
|
0 commit comments