]> git.lizzy.rs Git - rust.git/commitdiff
ADD - initial port of link.rs
authorJhonny Bill Mena <jhonnybillm@gmail.com>
Mon, 3 Oct 2022 03:21:15 +0000 (23:21 -0400)
committerJhonny Bill Mena <jhonnybillm@gmail.com>
Fri, 7 Oct 2022 14:03:45 +0000 (10:03 -0400)
compiler/rustc_codegen_ssa/src/back/link.rs
compiler/rustc_codegen_ssa/src/errors.rs
compiler/rustc_codegen_ssa/src/lib.rs
compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl

index 9a0c379b4e44d1b237913c31b3329338940e25d0..ac2a8f969df00cf7d3fba6bbe66f400c79647268 100644 (file)
@@ -31,7 +31,9 @@
 use super::linker::{self, Linker};
 use super::metadata::{create_rmeta_file, MetadataPosition};
 use super::rpath::{self, RPathConfig};
-use crate::{looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, NativeLib};
+use crate::{
+    errors, looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, NativeLib,
+};
 
 use cc::windows_registry;
 use regex::Regex;
@@ -93,7 +95,7 @@ pub fn link_binary<'a>(
             let tmpdir = TempFileBuilder::new()
                 .prefix("rustc")
                 .tempdir()
-                .unwrap_or_else(|err| sess.fatal(&format!("couldn't create a temp dir: {}", err)));
+                .unwrap_or_else(|error| sess.emit_fatal(errors::CreateTempDir { error }));
             let path = MaybeTempDir::new(tmpdir, sess.opts.cg.save_temps);
             let out_filename = out_filename(
                 sess,
@@ -208,7 +210,7 @@ pub fn link_binary<'a>(
 pub fn each_linked_rlib(
     info: &CrateInfo,
     f: &mut dyn FnMut(CrateNum, &Path),
-) -> Result<(), String> {
+) -> Result<(), errors::LinkRlibError> {
     let crates = info.used_crates.iter();
     let mut fmts = None;
     for (ty, list) in info.dependency_formats.iter() {
@@ -224,26 +226,23 @@ pub fn each_linked_rlib(
         }
     }
     let Some(fmts) = fmts else {
-        return Err("could not find formats for rlibs".to_string());
+        return Err(errors::LinkRlibError::MissingFormat);
     };
     for &cnum in crates {
         match fmts.get(cnum.as_usize() - 1) {
             Some(&Linkage::NotLinked | &Linkage::IncludedFromDylib) => continue,
             Some(_) => {}
-            None => return Err("could not find formats for rlibs".to_string()),
+            None => return Err(errors::LinkRlibError::MissingFormat),
         }
-        let name = info.crate_name[&cnum];
+        let crate_name = info.crate_name[&cnum];
         let used_crate_source = &info.used_crate_source[&cnum];
         if let Some((path, _)) = &used_crate_source.rlib {
             f(cnum, &path);
         } else {
             if used_crate_source.rmeta.is_some() {
-                return Err(format!(
-                    "could not find rlib for: `{}`, found rmeta (metadata) file",
-                    name
-                ));
+                return Err(errors::LinkRlibError::OnlyRmetaFound { crate_name });
             } else {
-                return Err(format!("could not find rlib for: `{}`", name));
+                return Err(errors::LinkRlibError::NotFound { crate_name });
             }
         }
     }
@@ -340,10 +339,7 @@ fn link_rlib<'a>(
                 // -whole-archive and it isn't clear how we can currently handle such a
                 // situation correctly.
                 // See https://github.com/rust-lang/rust/issues/88085#issuecomment-901050897
-                sess.err(
-                    "the linking modifiers `+bundle` and `+whole-archive` are not compatible \
-                        with each other when generating rlibs",
-                );
+                sess.emit_err(errors::IncompatibleLinkingModifiers);
             }
             NativeLibKind::Static { bundle: None | Some(true), .. } => {}
             NativeLibKind::Static { bundle: Some(false), .. }
@@ -365,12 +361,11 @@ fn link_rlib<'a>(
                 ));
                 continue;
             }
-            ab.add_archive(&location, Box::new(|_| false)).unwrap_or_else(|e| {
-                sess.fatal(&format!(
-                    "failed to add native library {}: {}",
-                    location.to_string_lossy(),
-                    e
-                ));
+            ab.add_archive(&location, Box::new(|_| false)).unwrap_or_else(|error| {
+                sess.emit_fatal(errors::AddNativeLibrary {
+                    library_path: &location.to_string_lossy(),
+                    error,
+                });
             });
         }
     }
@@ -385,8 +380,11 @@ fn link_rlib<'a>(
             tmpdir.as_ref(),
         );
 
-        ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|e| {
-            sess.fatal(&format!("failed to add native library {}: {}", output_path.display(), e));
+        ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|error| {
+            sess.emit_fatal(errors::AddNativeLibrary {
+                library_path: &output_path.display().to_string(),
+                error,
+            });
         });
     }
 
@@ -451,14 +449,11 @@ fn collate_raw_dylibs(
                     // FIXME: when we add support for ordinals, figure out if we need to do anything
                     // if we have two DllImport values with the same name but different ordinals.
                     if import.calling_convention != old_import.calling_convention {
-                        sess.span_err(
-                            import.span,
-                            &format!(
-                                "multiple declarations of external function `{}` from \
-                                 library `{}` have different calling conventions",
-                                import.name, name,
-                            ),
-                        );
+                        sess.emit_err(errors::MultipleExternalFuncDecl {
+                            span: import.span,
+                            function: import.name,
+                            library_name: &name,
+                        });
                     }
                 }
             }
@@ -560,7 +555,7 @@ fn link_staticlib<'a>(
         all_native_libs.extend(codegen_results.crate_info.native_libraries[&cnum].iter().cloned());
     });
     if let Err(e) = res {
-        sess.fatal(&e);
+        sess.emit_fatal(e);
     }
 
     ab.build(out_filename);
@@ -673,9 +668,8 @@ fn read_input<'arena>(&'arena self, path: &Path) -> std::io::Result<&'arena [u8]
     }) {
         Ok(()) => {}
         Err(e) => {
-            sess.struct_err("linking dwarf objects with thorin failed")
-                .note(&format!("{:?}", e))
-                .emit();
+            let thorin_error = errors::ThorinErrorWrapper(e);
+            sess.emit_err(errors::ThorinDwarfLinking { thorin_error });
             sess.abort_if_errors();
         }
     }
@@ -879,23 +873,14 @@ fn is_illegal_instruction(_status: &ExitStatus) -> bool {
                 let mut output = prog.stderr.clone();
                 output.extend_from_slice(&prog.stdout);
                 let escaped_output = escape_string(&output);
-                let mut err = sess.struct_err(&format!(
-                    "linking with `{}` failed: {}",
-                    linker_path.display(),
-                    prog.status
-                ));
-                err.note(&format!("{:?}", &cmd)).note(&escaped_output);
-                if escaped_output.contains("undefined reference to") {
-                    err.help(
-                        "some `extern` functions couldn't be found; some native libraries may \
-                         need to be installed or have their path specified",
-                    );
-                    err.note("use the `-l` flag to specify native libraries to link");
-                    err.note("use the `cargo:rustc-link-lib` directive to specify the native \
-                              libraries to link with Cargo (see https://doc.rust-lang.org/cargo/reference/build-scripts.html#cargorustc-link-libkindname)");
-                }
-                err.emit();
-
+                // FIXME: Add UI tests for this error.
+                let err = errors::LinkingFailed {
+                    linker_path: &linker_path,
+                    exit_status: prog.status,
+                    command: &cmd,
+                    escaped_output: &escaped_output,
+                };
+                sess.diagnostic().emit_err(err);
                 // If MSVC's `link.exe` was expected but the return code
                 // is not a Microsoft LNK error then suggest a way to fix or
                 // install the Visual Studio build tools.
index cf98cb2468ab7593b4443fdef07fdb54773139aa..6bd1dc2e03f66ed1747ffad5fc3019d09853cd6f 100644 (file)
@@ -1,10 +1,16 @@
 //! Errors emitted by codegen_ssa
 
-use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg};
+use crate::back::command::Command;
+use rustc_errors::{
+    fluent, DiagnosticArgValue, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic,
+    IntoDiagnosticArg,
+};
 use rustc_macros::Diagnostic;
+use rustc_span::{Span, Symbol};
 use std::borrow::Cow;
 use std::io::Error;
 use std::path::{Path, PathBuf};
+use std::process::ExitStatus;
 
 #[derive(Diagnostic)]
 #[diag(codegen_ssa::lib_def_write_failure)]
@@ -73,17 +79,15 @@ pub struct CopyPath<'a> {
 
 impl<'a> CopyPath<'a> {
     pub fn new(from: &'a Path, to: &'a Path, error: Error) -> CopyPath<'a> {
-        CopyPath { from: DebugArgPath { path: from }, to: DebugArgPath { path: to }, error }
+        CopyPath { from: DebugArgPath(from), to: DebugArgPath(to), error }
     }
 }
 
-struct DebugArgPath<'a> {
-    pub path: &'a Path,
-}
+struct DebugArgPath<'a>(pub &'a Path);
 
 impl IntoDiagnosticArg for DebugArgPath<'_> {
     fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
-        DiagnosticArgValue::Str(Cow::Owned(format!("{:?}", self.path)))
+        DiagnosticArgValue::Str(Cow::Owned(format!("{:?}", self.0)))
     }
 }
 
@@ -98,3 +102,96 @@ pub struct IgnoringEmitPath {
 pub struct IgnoringOutput {
     pub extension: String,
 }
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa::create_temp_dir)]
+pub struct CreateTempDir {
+    pub error: Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa::incompatible_linking_modifiers)]
+pub struct IncompatibleLinkingModifiers;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa::add_native_library)]
+pub struct AddNativeLibrary<'a> {
+    pub library_path: &'a str,
+    pub error: Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa::multiple_external_func_decl)]
+pub struct MultipleExternalFuncDecl<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub function: Symbol,
+    pub library_name: &'a str,
+}
+
+pub enum LinkRlibError {
+    MissingFormat,
+    OnlyRmetaFound { crate_name: Symbol },
+    NotFound { crate_name: Symbol },
+}
+
+impl IntoDiagnostic<'_, !> for LinkRlibError {
+    fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, !> {
+        match self {
+            LinkRlibError::MissingFormat => {
+                handler.struct_fatal(fluent::codegen_ssa::rlib_missing_format)
+            }
+            LinkRlibError::OnlyRmetaFound { crate_name } => {
+                let mut diag = handler.struct_fatal(fluent::codegen_ssa::rlib_only_rmeta_found);
+                diag.set_arg("crate_name", crate_name);
+                diag
+            }
+            LinkRlibError::NotFound { crate_name } => {
+                let mut diag = handler.struct_fatal(fluent::codegen_ssa::rlib_not_found);
+                diag.set_arg("crate_name", crate_name);
+                diag
+            }
+        }
+    }
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa::thorin_dwarf_linking)]
+#[note]
+pub struct ThorinDwarfLinking {
+    pub thorin_error: ThorinErrorWrapper,
+}
+pub struct ThorinErrorWrapper(pub thorin::Error);
+
+// FIXME: How should we support translations for external crate errors?
+impl IntoDiagnosticArg for ThorinErrorWrapper {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(Cow::Owned(format!("{:?}", self.0)))
+    }
+}
+
+pub struct LinkingFailed<'a> {
+    pub linker_path: &'a PathBuf,
+    pub exit_status: ExitStatus,
+    pub command: &'a Command,
+    pub escaped_output: &'a str,
+}
+
+impl IntoDiagnostic<'_> for LinkingFailed<'_> {
+    fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
+        let mut diag = handler.struct_err(fluent::codegen_ssa::linking_failed);
+        diag.set_arg("linker_path", format!("{}", self.linker_path.display()));
+        diag.set_arg("exit_status", format!("{}", self.exit_status));
+
+        diag.note(format!("{:?}", self.command)).note(self.escaped_output);
+
+        // Trying to match an error from OS linkers
+        // which by now we have no way to translate.
+        if self.escaped_output.contains("undefined reference to") {
+            diag.note(fluent::codegen_ssa::extern_funcs_not_found)
+                .note(fluent::codegen_ssa::specify_libraries_to_link)
+                .note(fluent::codegen_ssa::use_cargo_directive);
+        }
+        diag
+    }
+}
index e62b6f342b2e97f3aa4603bfc952786d37da9509..ceebe4d417f7d68b0014f8b75d80d6f150e97b36 100644 (file)
@@ -6,6 +6,7 @@
 #![feature(strict_provenance)]
 #![feature(int_roundings)]
 #![feature(if_let_guard)]
+#![feature(never_type)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
 
index 4d43b2eb0b69667af9b3aaf99735b81d4a2a6c39..d996a096a892ea67ab7dc29522a2845a326f731a 100644 (file)
@@ -25,3 +25,28 @@ codegen_ssa_copy_path_buf = unable to copy {$source_file} to {$output_path}: {$e
 codegen_ssa_ignoring_emit_path = ignoring emit path because multiple .{$extension} files were produced
 
 codegen_ssa_ignoring_output = ignoring -o because multiple .{$extension} files were produced
+
+codegen_ssa_create_temp_dir = couldn't create a temp dir: {$error}
+
+codegen_ssa_incompatible_linking_modifiers = the linking modifiers `+bundle` and `+whole-archive` are not compatible with each other when generating rlibs
+
+codegen_ssa_add_native_library = failed to add native library {$library_path}: {$error}
+
+codegen_ssa_multiple_external_func_decl = multiple declarations of external function `{$function}` from library `{$library_name}` have different calling conventions
+
+codegen_ssa_rlib_missing_format = could not find formats for rlibs
+
+codegen_ssa_rlib_only_rmeta_found = could not find rlib for: `{$crate_name}`, found rmeta (metadata) file
+
+codegen_ssa_rlib_not_found = could not find rlib for: `{$crate_name}`
+
+codegen_ssa_thorin_dwarf_linking = linking dwarf objects with thorin failed
+    .note = {$thorin_error}
+
+codegen_ssa_linking_failed = linking with `{$linker_path}` failed: {$exit_status}
+
+codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified
+
+codegen_ssa_specify_libraries_to_link = use the `-l` flag to specify native libraries to link
+
+codegen_ssa_use_cargo_directive = use the `cargo:rustc-link-lib` directive to specify the native libraries to link with Cargo (see https://doc.rust-lang.org/cargo/reference/build-scripts.html#cargorustc-link-libkindname)