Skip to content

Commit 3c3ab25

Browse files
committed
Do not use dlltool to create DLL Import Libraries for Windows
1 parent 94ecb52 commit 3c3ab25

File tree

6 files changed

+53
-227
lines changed

6 files changed

+53
-227
lines changed

compiler/rustc_codegen_ssa/messages.ftl

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,26 +28,15 @@ codegen_ssa_cpu_required = target requires explicitly specifying a cpu with `-C
2828
2929
codegen_ssa_create_temp_dir = couldn't create a temp dir: {$error}
3030
31-
codegen_ssa_dlltool_fail_import_library =
32-
dlltool could not create import library with {$dlltool_path} {$dlltool_args}:
33-
{$stdout}
34-
{$stderr}
35-
3631
codegen_ssa_dynamic_linking_with_lto =
3732
cannot prefer dynamic linking when performing LTO
3833
.note = only 'staticlib', 'bin', and 'cdylib' outputs are supported with LTO
3934
40-
codegen_ssa_error_calling_dlltool =
41-
error calling dlltool '{$dlltool_path}': {$error}
42-
4335
codegen_ssa_error_creating_import_library =
4436
error creating import library for {$lib_name}: {$error}
4537
4638
codegen_ssa_error_creating_remark_dir = failed to create remark directory: {$error}
4739
48-
codegen_ssa_error_writing_def_file =
49-
error writing .DEF file: {$error}
50-
5140
codegen_ssa_expected_name_value_pair = expected name value pair
5241
5342
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

compiler/rustc_codegen_ssa/src/back/archive.rs

Lines changed: 52 additions & 190 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
use std::env;
21
use std::error::Error;
3-
use std::ffi::OsString;
42
use std::fs::{self, File};
53
use std::io::{self, BufWriter, Write};
64
use std::path::{Path, PathBuf};
@@ -20,12 +18,9 @@ use rustc_span::Symbol;
2018
use tracing::trace;
2119

2220
use super::metadata::{create_compressed_metadata_file, search_for_section};
23-
use crate::common;
21+
use crate::errors::ErrorCreatingImportLibrary;
2422
// Re-exporting for rustc_codegen_llvm::back::archive
2523
pub use crate::errors::{ArchiveBuildFailure, ExtractBundledLibsError, UnknownArchiveKind};
26-
use crate::errors::{
27-
DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorCreatingImportLibrary, ErrorWritingDEFFile,
28-
};
2924

3025
/// An item to be included in an import library.
3126
/// This is a slimmed down version of `COFFShortExport` from `ar-archive-writer`.
@@ -82,66 +77,57 @@ pub trait ArchiveBuilderBuilder {
8277
items: Vec<ImportLibraryItem>,
8378
output_path: &Path,
8479
) {
85-
if common::is_mingw_gnu_toolchain(&sess.target) {
86-
// The binutils linker used on -windows-gnu targets cannot read the import
87-
// libraries generated by LLVM: in our attempts, the linker produced an .EXE
88-
// that loaded but crashed with an AV upon calling one of the imported
89-
// functions. Therefore, use binutils to create the import library instead,
90-
// by writing a .DEF file to the temp dir and calling binutils's dlltool.
91-
create_mingw_dll_import_lib(sess, lib_name, items, output_path);
92-
} else {
93-
trace!("creating import library");
94-
trace!(" dll_name {:#?}", lib_name);
95-
trace!(" output_path {}", output_path.display());
96-
trace!(
97-
" import names: {}",
98-
items
99-
.iter()
100-
.map(|ImportLibraryItem { name, .. }| name.clone())
101-
.collect::<Vec<_>>()
102-
.join(", "),
103-
);
104-
105-
// All import names are Rust identifiers and therefore cannot contain \0 characters.
106-
// FIXME: when support for #[link_name] is implemented, ensure that the import names
107-
// still don't contain any \0 characters. Also need to check that the names don't
108-
// contain substrings like " @" or "NONAME" that are keywords or otherwise reserved
109-
// in definition files.
110-
111-
let mut file = match fs::File::create_new(&output_path) {
112-
Ok(file) => file,
113-
Err(error) => sess
114-
.dcx()
115-
.emit_fatal(ErrorCreatingImportLibrary { lib_name, error: error.to_string() }),
116-
};
117-
118-
let exports =
119-
items.into_iter().map(|item| item.into_coff_short_export(sess)).collect::<Vec<_>>();
120-
let machine = match &*sess.target.arch {
121-
"x86_64" => MachineTypes::AMD64,
122-
"x86" => MachineTypes::I386,
123-
"aarch64" => MachineTypes::ARM64,
124-
"arm64ec" => MachineTypes::ARM64EC,
125-
"arm" => MachineTypes::ARMNT,
126-
cpu => panic!("unsupported cpu type {cpu}"),
127-
};
128-
129-
if let Err(error) = ar_archive_writer::write_import_library(
130-
&mut file,
131-
lib_name,
132-
&exports,
133-
machine,
134-
!sess.target.is_like_msvc,
135-
// Enable compatibility with MSVC's `/WHOLEARCHIVE` flag.
136-
// Without this flag a duplicate symbol error would be emitted
137-
// when linking a rust staticlib using `/WHOLEARCHIVE`.
138-
// See #129020
139-
true,
140-
&[],
141-
) {
142-
sess.dcx()
143-
.emit_fatal(ErrorCreatingImportLibrary { lib_name, error: error.to_string() });
144-
}
80+
trace!("creating import library");
81+
trace!(" dll_name {:#?}", lib_name);
82+
trace!(" output_path {}", output_path.display());
83+
trace!(
84+
" import names: {}",
85+
items
86+
.iter()
87+
.map(|ImportLibraryItem { name, .. }| name.clone())
88+
.collect::<Vec<_>>()
89+
.join(", "),
90+
);
91+
92+
// All import names are Rust identifiers and therefore cannot contain \0 characters.
93+
// FIXME: when support for #[link_name] is implemented, ensure that the import names
94+
// still don't contain any \0 characters. Also need to check that the names don't
95+
// contain substrings like " @" or "NONAME" that are keywords or otherwise reserved
96+
// in definition files.
97+
98+
let mut file = match fs::File::create_new(&output_path) {
99+
Ok(file) => file,
100+
Err(error) => sess
101+
.dcx()
102+
.emit_fatal(ErrorCreatingImportLibrary { lib_name, error: error.to_string() }),
103+
};
104+
105+
let exports =
106+
items.into_iter().map(|item| item.into_coff_short_export(sess)).collect::<Vec<_>>();
107+
let machine = match &*sess.target.arch {
108+
"x86_64" => MachineTypes::AMD64,
109+
"x86" => MachineTypes::I386,
110+
"aarch64" => MachineTypes::ARM64,
111+
"arm64ec" => MachineTypes::ARM64EC,
112+
"arm" => MachineTypes::ARMNT,
113+
cpu => panic!("unsupported cpu type {cpu}"),
114+
};
115+
116+
if let Err(error) = ar_archive_writer::write_import_library(
117+
&mut file,
118+
lib_name,
119+
&exports,
120+
machine,
121+
!sess.target.is_like_msvc,
122+
// Enable compatibility with MSVC's `/WHOLEARCHIVE` flag.
123+
// Without this flag a duplicate symbol error would be emitted
124+
// when linking a rust staticlib using `/WHOLEARCHIVE`.
125+
// See #129020
126+
true,
127+
&[],
128+
) {
129+
sess.dcx()
130+
.emit_fatal(ErrorCreatingImportLibrary { lib_name, error: error.to_string() });
145131
}
146132
}
147133

@@ -182,130 +168,6 @@ pub trait ArchiveBuilderBuilder {
182168
}
183169
}
184170

185-
fn create_mingw_dll_import_lib(
186-
sess: &Session,
187-
lib_name: &str,
188-
items: Vec<ImportLibraryItem>,
189-
output_path: &Path,
190-
) {
191-
let def_file_path = output_path.with_extension("def");
192-
193-
let def_file_content = format!(
194-
"EXPORTS\n{}",
195-
items
196-
.into_iter()
197-
.map(|ImportLibraryItem { name, ordinal, .. }| {
198-
match ordinal {
199-
Some(n) => format!("{name} @{n} NONAME"),
200-
None => name,
201-
}
202-
})
203-
.collect::<Vec<String>>()
204-
.join("\n")
205-
);
206-
207-
match std::fs::write(&def_file_path, def_file_content) {
208-
Ok(_) => {}
209-
Err(e) => {
210-
sess.dcx().emit_fatal(ErrorWritingDEFFile { error: e });
211-
}
212-
};
213-
214-
// --no-leading-underscore: For the `import_name_type` feature to work, we need to be
215-
// able to control the *exact* spelling of each of the symbols that are being imported:
216-
// hence we don't want `dlltool` adding leading underscores automatically.
217-
let dlltool = find_binutils_dlltool(sess);
218-
let temp_prefix = {
219-
let mut path = PathBuf::from(&output_path);
220-
path.pop();
221-
path.push(lib_name);
222-
path
223-
};
224-
// dlltool target architecture args from:
225-
// https://github.com/llvm/llvm-project-release-prs/blob/llvmorg-15.0.6/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp#L69
226-
let (dlltool_target_arch, dlltool_target_bitness) = match sess.target.arch.as_ref() {
227-
"x86_64" => ("i386:x86-64", "--64"),
228-
"x86" => ("i386", "--32"),
229-
"aarch64" => ("arm64", "--64"),
230-
"arm" => ("arm", "--32"),
231-
_ => panic!("unsupported arch {}", sess.target.arch),
232-
};
233-
let mut dlltool_cmd = std::process::Command::new(&dlltool);
234-
dlltool_cmd
235-
.arg("-d")
236-
.arg(def_file_path)
237-
.arg("-D")
238-
.arg(lib_name)
239-
.arg("-l")
240-
.arg(&output_path)
241-
.arg("-m")
242-
.arg(dlltool_target_arch)
243-
.arg("-f")
244-
.arg(dlltool_target_bitness)
245-
.arg("--no-leading-underscore")
246-
.arg("--temp-prefix")
247-
.arg(temp_prefix);
248-
249-
match dlltool_cmd.output() {
250-
Err(e) => {
251-
sess.dcx().emit_fatal(ErrorCallingDllTool {
252-
dlltool_path: dlltool.to_string_lossy(),
253-
error: e,
254-
});
255-
}
256-
// dlltool returns '0' on failure, so check for error output instead.
257-
Ok(output) if !output.stderr.is_empty() => {
258-
sess.dcx().emit_fatal(DlltoolFailImportLibrary {
259-
dlltool_path: dlltool.to_string_lossy(),
260-
dlltool_args: dlltool_cmd
261-
.get_args()
262-
.map(|arg| arg.to_string_lossy())
263-
.collect::<Vec<_>>()
264-
.join(" "),
265-
stdout: String::from_utf8_lossy(&output.stdout),
266-
stderr: String::from_utf8_lossy(&output.stderr),
267-
})
268-
}
269-
_ => {}
270-
}
271-
}
272-
273-
fn find_binutils_dlltool(sess: &Session) -> OsString {
274-
assert!(sess.target.options.is_like_windows && !sess.target.options.is_like_msvc);
275-
if let Some(dlltool_path) = &sess.opts.cg.dlltool {
276-
return dlltool_path.clone().into_os_string();
277-
}
278-
279-
let tool_name: OsString = if sess.host.options.is_like_windows {
280-
// If we're compiling on Windows, always use "dlltool.exe".
281-
"dlltool.exe"
282-
} else {
283-
// On other platforms, use the architecture-specific name.
284-
match sess.target.arch.as_ref() {
285-
"x86_64" => "x86_64-w64-mingw32-dlltool",
286-
"x86" => "i686-w64-mingw32-dlltool",
287-
"aarch64" => "aarch64-w64-mingw32-dlltool",
288-
289-
// For non-standard architectures (e.g., aarch32) fallback to "dlltool".
290-
_ => "dlltool",
291-
}
292-
}
293-
.into();
294-
295-
// NOTE: it's not clear how useful it is to explicitly search PATH.
296-
for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) {
297-
let full_path = dir.join(&tool_name);
298-
if full_path.is_file() {
299-
return full_path.into_os_string();
300-
}
301-
}
302-
303-
// The user didn't specify the location of the dlltool binary, and we weren't able
304-
// to find the appropriate one on the PATH. Just return the name of the tool
305-
// and let the invocation fail with a hopefully useful error message.
306-
tool_name
307-
}
308-
309171
pub trait ArchiveBuilder {
310172
fn add_file(&mut self, path: &Path);
311173

compiler/rustc_codegen_ssa/src/errors.rs

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1144,28 +1144,6 @@ pub struct FailedToGetLayout<'tcx> {
11441144
pub err: LayoutError<'tcx>,
11451145
}
11461146

1147-
#[derive(Diagnostic)]
1148-
#[diag(codegen_ssa_dlltool_fail_import_library)]
1149-
pub(crate) struct DlltoolFailImportLibrary<'a> {
1150-
pub dlltool_path: Cow<'a, str>,
1151-
pub dlltool_args: String,
1152-
pub stdout: Cow<'a, str>,
1153-
pub stderr: Cow<'a, str>,
1154-
}
1155-
1156-
#[derive(Diagnostic)]
1157-
#[diag(codegen_ssa_error_writing_def_file)]
1158-
pub(crate) struct ErrorWritingDEFFile {
1159-
pub error: std::io::Error,
1160-
}
1161-
1162-
#[derive(Diagnostic)]
1163-
#[diag(codegen_ssa_error_calling_dlltool)]
1164-
pub(crate) struct ErrorCallingDllTool<'a> {
1165-
pub dlltool_path: Cow<'a, str>,
1166-
pub error: std::io::Error,
1167-
}
1168-
11691147
#[derive(Diagnostic)]
11701148
#[diag(codegen_ssa_error_creating_remark_dir)]
11711149
pub(crate) struct ErrorCreatingRemarkDir {

compiler/rustc_interface/src/tests.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -584,7 +584,6 @@ fn test_codegen_options_tracking_hash() {
584584
untracked!(ar, String::from("abc"));
585585
untracked!(codegen_units, Some(42));
586586
untracked!(default_linker_libraries, true);
587-
untracked!(dlltool, Some(PathBuf::from("custom_dlltool.exe")));
588587
untracked!(extra_filename, String::from("extra-filename"));
589588
untracked!(incremental, Some(String::from("abc")));
590589
untracked!(inline_threshold, Some(0xf007ba11));

compiler/rustc_session/src/options.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2067,8 +2067,6 @@ options! {
20672067
line-tables-only, limited, or full; default: 0)"),
20682068
default_linker_libraries: bool = (false, parse_bool, [UNTRACKED],
20692069
"allow the linker to link its default libraries (default: no)"),
2070-
dlltool: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
2071-
"import library generation tool (ignored except when targeting windows-gnu)"),
20722070
#[rustc_lint_opt_deny_field_access("use `Session::dwarf_version` instead of this field")]
20732071
dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED],
20742072
"version of DWARF debug information to emit (default: 2 or 4, depending on platform)"),

compiler/rustc_target/src/spec/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -659,7 +659,7 @@ bitflags::bitflags! {
659659
const LIBC = 1 << 1;
660660
/// libgcc/libunwind (e.g. on `windows-gnu`, `fuchsia`, `fortanix`, `gnullvm` targets)
661661
const UNWIND = 1 << 2;
662-
/// Linker, dlltool, and their necessary libraries (e.g. on `windows-gnu` and for `rust-lld`)
662+
/// Linker and its necessary libraries (e.g. on `windows-gnu` and for `rust-lld`)
663663
const LINKER = 1 << 3;
664664
/// Sanitizer runtime libraries
665665
const SANITIZERS = 1 << 4;

0 commit comments

Comments
 (0)