ADD - initial port of link.rs

This commit is contained in:
Jhonny Bill Mena 2022-10-02 23:21:15 -04:00
parent 0f97d4a141
commit 12aa84bdf3
4 changed files with 166 additions and 58 deletions

View File

@ -31,7 +31,9 @@ use super::command::Command;
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 link_dwarf_object<'a>(
}) {
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 link_natively<'a>(
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.

View 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
}
}

View 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)]

View 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)