| 
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