Skip to content

Commit

Permalink
Rollup merge of #128206 - bjorn3:import_lib_writing_refactor, r=jieyouxu
Browse files Browse the repository at this point in the history
Make create_dll_import_lib easier to implement

This will make it easier to implement raw-dylib support in cg_clif and cg_gcc. This PR doesn't yet include an create_dll_import_lib implementation for cg_clif as I need to correctly implement dllimport in cg_clif first before raw-dylib can work at all with cg_clif.

Required for rust-lang/rustc_codegen_cranelift#1345
  • Loading branch information
GuillaumeGomez authored Aug 7, 2024
2 parents 9bad7ba + f58e737 commit 355eb9c
Show file tree
Hide file tree
Showing 15 changed files with 332 additions and 317 deletions.
15 changes: 3 additions & 12 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -205,11 +205,11 @@ dependencies = [

[[package]]
name = "ar_archive_writer"
version = "0.3.0"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8412a2d690663356cba5a2532f3ed55d1e8090743bc6695b88403b27df67733"
checksum = "3f2bcb7cf51decfbbfc7ef476e28b0775b13e5eb1190f8b7df145cd53d4f4374"
dependencies = [
"object 0.35.0",
"object 0.36.2",
]

[[package]]
Expand Down Expand Up @@ -2454,15 +2454,6 @@ dependencies = [
"ruzstd 0.5.0",
]

[[package]]
name = "object"
version = "0.35.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e"
dependencies = [
"memchr",
]

[[package]]
name = "object"
version = "0.36.2"
Expand Down
9 changes: 4 additions & 5 deletions compiler/rustc_codegen_cranelift/src/archive.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::path::{Path, PathBuf};
use std::path::Path;

use rustc_codegen_ssa::back::archive::{
ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER,
Expand All @@ -16,10 +16,9 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
&self,
sess: &Session,
_lib_name: &str,
_dll_imports: &[rustc_session::cstore::DllImport],
_tmpdir: &Path,
_is_direct_dependency: bool,
) -> PathBuf {
_import_name_and_ordinal_vector: Vec<(String, Option<u16>)>,
_output_path: &Path,
) {
sess.dcx().fatal("raw-dylib is not yet supported by rustc_codegen_cranelift");
}
}
10 changes: 4 additions & 6 deletions compiler/rustc_codegen_gcc/src/archive.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use std::path::{Path, PathBuf};
use std::path::Path;

use rustc_codegen_ssa::back::archive::{
ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER,
};
use rustc_session::cstore::DllImport;
use rustc_session::Session;

pub(crate) struct ArArchiveBuilderBuilder;
Expand All @@ -17,10 +16,9 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
&self,
_sess: &Session,
_lib_name: &str,
_dll_imports: &[DllImport],
_tmpdir: &Path,
_is_direct_dependency: bool,
) -> PathBuf {
_import_name_and_ordinal_vector: Vec<(String, Option<u16>)>,
_output_path: &Path,
) {
unimplemented!("creating dll imports is not yet supported");
}
}
10 changes: 0 additions & 10 deletions compiler/rustc_codegen_llvm/messages.ftl
Original file line number Diff line number Diff line change
@@ -1,23 +1,13 @@
codegen_llvm_copy_bitcode = failed to copy bitcode to object file: {$err}
codegen_llvm_dlltool_fail_import_library =
Dlltool could not create import library with {$dlltool_path} {$dlltool_args}:
{$stdout}
{$stderr}
codegen_llvm_dynamic_linking_with_lto =
cannot prefer dynamic linking when performing LTO
.note = only 'staticlib', 'bin', and 'cdylib' outputs are supported with LTO
codegen_llvm_error_calling_dlltool =
Error calling dlltool '{$dlltool_path}': {$error}
codegen_llvm_error_creating_import_library =
Error creating import library for {$lib_name}: {$error}
codegen_llvm_error_writing_def_file =
Error writing .DEF file: {$error}
codegen_llvm_fixed_x18_invalid_arch = the `-Zfixed-x18` flag is not supported on the `{$arch}` architecture
codegen_llvm_from_llvm_diag = {$message}
Expand Down
173 changes: 19 additions & 154 deletions compiler/rustc_codegen_llvm/src/back/archive.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
//! A helper class for dealing with static archives

use std::ffi::{c_char, c_void, CStr, CString, OsString};
use std::ffi::{c_char, c_void, CStr, CString};
use std::path::{Path, PathBuf};
use std::{env, io, mem, ptr, str};
use std::{io, mem, ptr, str};

use rustc_codegen_ssa::back::archive::{
try_extract_macho_fat_archive, ArArchiveBuilder, ArchiveBuildFailure, ArchiveBuilder,
ArchiveBuilderBuilder, ObjectReader, UnknownArchiveKind, DEFAULT_OBJECT_READER,
create_mingw_dll_import_lib, try_extract_macho_fat_archive, ArArchiveBuilder,
ArchiveBuildFailure, ArchiveBuilder, ArchiveBuilderBuilder, ObjectReader, UnknownArchiveKind,
DEFAULT_OBJECT_READER,
};
use rustc_session::cstore::DllImport;
use rustc_codegen_ssa::common;
use rustc_session::Session;
use tracing::trace;

use crate::common;
use crate::errors::{
DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorCreatingImportLibrary, ErrorWritingDEFFile,
};
use crate::errors::ErrorCreatingImportLibrary;
use crate::llvm::archive_ro::{ArchiveRO, Child};
use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};

Expand Down Expand Up @@ -121,116 +119,21 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
&self,
sess: &Session,
lib_name: &str,
dll_imports: &[DllImport],
tmpdir: &Path,
is_direct_dependency: bool,
) -> PathBuf {
let name_suffix = if is_direct_dependency { "_imports" } else { "_imports_indirect" };
let output_path = tmpdir.join(format!("{lib_name}{name_suffix}.lib"));

let target = &sess.target;
let mingw_gnu_toolchain = common::is_mingw_gnu_toolchain(target);

let import_name_and_ordinal_vector: Vec<(String, Option<u16>)> = dll_imports
.iter()
.map(|import: &DllImport| {
if sess.target.arch == "x86" {
(
common::i686_decorated_name(import, mingw_gnu_toolchain, false),
import.ordinal(),
)
} else {
(import.name.to_string(), import.ordinal())
}
})
.collect();

if mingw_gnu_toolchain {
import_name_and_ordinal_vector: Vec<(String, Option<u16>)>,
output_path: &Path,
) {
if common::is_mingw_gnu_toolchain(&sess.target) {
// The binutils linker used on -windows-gnu targets cannot read the import
// libraries generated by LLVM: in our attempts, the linker produced an .EXE
// that loaded but crashed with an AV upon calling one of the imported
// functions. Therefore, use binutils to create the import library instead,
// by writing a .DEF file to the temp dir and calling binutils's dlltool.
let def_file_path = tmpdir.join(format!("{lib_name}{name_suffix}.def"));

let def_file_content = format!(
"EXPORTS\n{}",
import_name_and_ordinal_vector
.into_iter()
.map(|(name, ordinal)| {
match ordinal {
Some(n) => format!("{name} @{n} NONAME"),
None => name,
}
})
.collect::<Vec<String>>()
.join("\n")
create_mingw_dll_import_lib(
sess,
lib_name,
import_name_and_ordinal_vector,
output_path,
);

match std::fs::write(&def_file_path, def_file_content) {
Ok(_) => {}
Err(e) => {
sess.dcx().emit_fatal(ErrorWritingDEFFile { error: e });
}
};

// --no-leading-underscore: For the `import_name_type` feature to work, we need to be
// able to control the *exact* spelling of each of the symbols that are being imported:
// hence we don't want `dlltool` adding leading underscores automatically.
let dlltool = find_binutils_dlltool(sess);
let temp_prefix = {
let mut path = PathBuf::from(&output_path);
path.pop();
path.push(lib_name);
path
};
// dlltool target architecture args from:
// https://github.com/llvm/llvm-project-release-prs/blob/llvmorg-15.0.6/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp#L69
let (dlltool_target_arch, dlltool_target_bitness) = match sess.target.arch.as_ref() {
"x86_64" => ("i386:x86-64", "--64"),
"x86" => ("i386", "--32"),
"aarch64" => ("arm64", "--64"),
"arm" => ("arm", "--32"),
_ => panic!("unsupported arch {}", sess.target.arch),
};
let mut dlltool_cmd = std::process::Command::new(&dlltool);
dlltool_cmd
.arg("-d")
.arg(def_file_path)
.arg("-D")
.arg(lib_name)
.arg("-l")
.arg(&output_path)
.arg("-m")
.arg(dlltool_target_arch)
.arg("-f")
.arg(dlltool_target_bitness)
.arg("--no-leading-underscore")
.arg("--temp-prefix")
.arg(temp_prefix);

match dlltool_cmd.output() {
Err(e) => {
sess.dcx().emit_fatal(ErrorCallingDllTool {
dlltool_path: dlltool.to_string_lossy(),
error: e,
});
}
// dlltool returns '0' on failure, so check for error output instead.
Ok(output) if !output.stderr.is_empty() => {
sess.dcx().emit_fatal(DlltoolFailImportLibrary {
dlltool_path: dlltool.to_string_lossy(),
dlltool_args: dlltool_cmd
.get_args()
.map(|arg| arg.to_string_lossy())
.collect::<Vec<_>>()
.join(" "),
stdout: String::from_utf8_lossy(&output.stdout),
stderr: String::from_utf8_lossy(&output.stderr),
})
}
_ => {}
}
} else {
// we've checked for \0 characters in the library name already
let dll_name_z = CString::new(lib_name).unwrap();
Expand All @@ -242,9 +145,9 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
trace!(" output_path {}", output_path.display());
trace!(
" import names: {}",
dll_imports
import_name_and_ordinal_vector
.iter()
.map(|import| import.name.to_string())
.map(|(name, _ordinal)| name.clone())
.collect::<Vec<_>>()
.join(", "),
);
Expand Down Expand Up @@ -281,9 +184,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
error: llvm::last_error().unwrap_or("unknown LLVM error".to_string()),
});
}
};

output_path
}
}
}

Expand Down Expand Up @@ -457,39 +358,3 @@ impl<'a> LlvmArchiveBuilder<'a> {
fn string_to_io_error(s: String) -> io::Error {
io::Error::new(io::ErrorKind::Other, format!("bad archive: {s}"))
}

fn find_binutils_dlltool(sess: &Session) -> OsString {
assert!(sess.target.options.is_like_windows && !sess.target.options.is_like_msvc);
if let Some(dlltool_path) = &sess.opts.cg.dlltool {
return dlltool_path.clone().into_os_string();
}

let tool_name: OsString = if sess.host.options.is_like_windows {
// If we're compiling on Windows, always use "dlltool.exe".
"dlltool.exe"
} else {
// On other platforms, use the architecture-specific name.
match sess.target.arch.as_ref() {
"x86_64" => "x86_64-w64-mingw32-dlltool",
"x86" => "i686-w64-mingw32-dlltool",
"aarch64" => "aarch64-w64-mingw32-dlltool",

// For non-standard architectures (e.g., aarch32) fallback to "dlltool".
_ => "dlltool",
}
}
.into();

// NOTE: it's not clear how useful it is to explicitly search PATH.
for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) {
let full_path = dir.join(&tool_name);
if full_path.is_file() {
return full_path.into_os_string();
}
}

// The user didn't specify the location of the dlltool binary, and we weren't able
// to find the appropriate one on the PATH. Just return the name of the tool
// and let the invocation fail with a hopefully useful error message.
tool_name
}
5 changes: 3 additions & 2 deletions compiler/rustc_codegen_llvm/src/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
//! and methods are represented as just a fn ptr and not a full
//! closure.

use rustc_codegen_ssa::common;
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
use rustc_middle::ty::{self, Instance, TypeVisitableExt};
use tracing::debug;

use crate::context::CodegenCx;
use crate::value::Value;
use crate::{attributes, common, llvm};
use crate::{attributes, llvm};

/// Codegens a reference to a fn/method item, monomorphizing and
/// inlining as it goes.
Expand Down Expand Up @@ -46,7 +47,7 @@ pub fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) ->
} else {
let instance_def_id = instance.def_id();
let llfn = if tcx.sess.target.arch == "x86"
&& let Some(dllimport) = common::get_dllimport(tcx, instance_def_id, sym)
&& let Some(dllimport) = crate::common::get_dllimport(tcx, instance_def_id, sym)
{
// Fix for https://github.com/rust-lang/rust/issues/104453
// On x86 Windows, LLVM uses 'L' as the prefix for any private
Expand Down
Loading

0 comments on commit 355eb9c

Please sign in to comment.