mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
ADD - initial port of link.rs
This commit is contained in:
parent
0f97d4a141
commit
12aa84bdf3
@ -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.
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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)]
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user