Skip to content

Commit 8cce076

Browse files
committed
Move mingw dlltool invocation to cg_ssa
1 parent c628985 commit 8cce076

File tree

6 files changed

+171
-159
lines changed

6 files changed

+171
-159
lines changed

compiler/rustc_codegen_llvm/messages.ftl

-10
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,13 @@
11
codegen_llvm_copy_bitcode = failed to copy bitcode to object file: {$err}
22
3-
codegen_llvm_dlltool_fail_import_library =
4-
Dlltool could not create import library with {$dlltool_path} {$dlltool_args}:
5-
{$stdout}
6-
{$stderr}
7-
83
codegen_llvm_dynamic_linking_with_lto =
94
cannot prefer dynamic linking when performing LTO
105
.note = only 'staticlib', 'bin', and 'cdylib' outputs are supported with LTO
116
12-
codegen_llvm_error_calling_dlltool =
13-
Error calling dlltool '{$dlltool_path}': {$error}
147
158
codegen_llvm_error_creating_import_library =
169
Error creating import library for {$lib_name}: {$error}
1710
18-
codegen_llvm_error_writing_def_file =
19-
Error writing .DEF file: {$error}
20-
2111
codegen_llvm_fixed_x18_invalid_arch = the `-Zfixed-x18` flag is not supported on the `{$arch}` architecture
2212
2313
codegen_llvm_from_llvm_diag = {$message}

compiler/rustc_codegen_llvm/src/back/archive.rs

+11-126
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
11
//! A helper class for dealing with static archives
22
3-
use std::env;
4-
use std::ffi::{c_char, c_void, CStr, CString, OsString};
3+
use std::ffi::{c_char, c_void, CStr, CString};
54
use std::io;
65
use std::mem;
76
use std::path::{Path, PathBuf};
87
use std::ptr;
98
use std::str;
109

11-
use crate::errors::{
12-
DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorCreatingImportLibrary, ErrorWritingDEFFile,
13-
};
10+
use crate::errors::ErrorCreatingImportLibrary;
1411
use crate::llvm::archive_ro::{ArchiveRO, Child};
1512
use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};
1613
use rustc_codegen_ssa::back::archive::{
17-
try_extract_macho_fat_archive, ArArchiveBuilder, ArchiveBuildFailure, ArchiveBuilder,
18-
ArchiveBuilderBuilder, ObjectReader, UnknownArchiveKind, DEFAULT_OBJECT_READER,
14+
create_mingw_dll_import_lib, try_extract_macho_fat_archive, ArArchiveBuilder,
15+
ArchiveBuildFailure, ArchiveBuilder, ArchiveBuilderBuilder, ObjectReader, UnknownArchiveKind,
16+
DEFAULT_OBJECT_READER,
1917
};
2018
use rustc_codegen_ssa::common;
2119
use tracing::trace;
@@ -125,95 +123,18 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
125123
import_name_and_ordinal_vector: Vec<(String, Option<u16>)>,
126124
output_path: &Path,
127125
) {
128-
let target = &sess.target;
129-
let mingw_gnu_toolchain = common::is_mingw_gnu_toolchain(target);
130-
131-
if mingw_gnu_toolchain {
126+
if common::is_mingw_gnu_toolchain(&sess.target) {
132127
// The binutils linker used on -windows-gnu targets cannot read the import
133128
// libraries generated by LLVM: in our attempts, the linker produced an .EXE
134129
// that loaded but crashed with an AV upon calling one of the imported
135130
// functions. Therefore, use binutils to create the import library instead,
136131
// by writing a .DEF file to the temp dir and calling binutils's dlltool.
137-
let def_file_path = output_path.with_extension("def");
138-
139-
let def_file_content = format!(
140-
"EXPORTS\n{}",
141-
import_name_and_ordinal_vector
142-
.into_iter()
143-
.map(|(name, ordinal)| {
144-
match ordinal {
145-
Some(n) => format!("{name} @{n} NONAME"),
146-
None => name,
147-
}
148-
})
149-
.collect::<Vec<String>>()
150-
.join("\n")
132+
create_mingw_dll_import_lib(
133+
sess,
134+
lib_name,
135+
import_name_and_ordinal_vector,
136+
output_path,
151137
);
152-
153-
match std::fs::write(&def_file_path, def_file_content) {
154-
Ok(_) => {}
155-
Err(e) => {
156-
sess.dcx().emit_fatal(ErrorWritingDEFFile { error: e });
157-
}
158-
};
159-
160-
// --no-leading-underscore: For the `import_name_type` feature to work, we need to be
161-
// able to control the *exact* spelling of each of the symbols that are being imported:
162-
// hence we don't want `dlltool` adding leading underscores automatically.
163-
let dlltool = find_binutils_dlltool(sess);
164-
let temp_prefix = {
165-
let mut path = PathBuf::from(&output_path);
166-
path.pop();
167-
path.push(lib_name);
168-
path
169-
};
170-
// dlltool target architecture args from:
171-
// https://github.com/llvm/llvm-project-release-prs/blob/llvmorg-15.0.6/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp#L69
172-
let (dlltool_target_arch, dlltool_target_bitness) = match sess.target.arch.as_ref() {
173-
"x86_64" => ("i386:x86-64", "--64"),
174-
"x86" => ("i386", "--32"),
175-
"aarch64" => ("arm64", "--64"),
176-
"arm" => ("arm", "--32"),
177-
_ => panic!("unsupported arch {}", sess.target.arch),
178-
};
179-
let mut dlltool_cmd = std::process::Command::new(&dlltool);
180-
dlltool_cmd
181-
.arg("-d")
182-
.arg(def_file_path)
183-
.arg("-D")
184-
.arg(lib_name)
185-
.arg("-l")
186-
.arg(&output_path)
187-
.arg("-m")
188-
.arg(dlltool_target_arch)
189-
.arg("-f")
190-
.arg(dlltool_target_bitness)
191-
.arg("--no-leading-underscore")
192-
.arg("--temp-prefix")
193-
.arg(temp_prefix);
194-
195-
match dlltool_cmd.output() {
196-
Err(e) => {
197-
sess.dcx().emit_fatal(ErrorCallingDllTool {
198-
dlltool_path: dlltool.to_string_lossy(),
199-
error: e,
200-
});
201-
}
202-
// dlltool returns '0' on failure, so check for error output instead.
203-
Ok(output) if !output.stderr.is_empty() => {
204-
sess.dcx().emit_fatal(DlltoolFailImportLibrary {
205-
dlltool_path: dlltool.to_string_lossy(),
206-
dlltool_args: dlltool_cmd
207-
.get_args()
208-
.map(|arg| arg.to_string_lossy())
209-
.collect::<Vec<_>>()
210-
.join(" "),
211-
stdout: String::from_utf8_lossy(&output.stdout),
212-
stderr: String::from_utf8_lossy(&output.stderr),
213-
})
214-
}
215-
_ => {}
216-
}
217138
} else {
218139
// we've checked for \0 characters in the library name already
219140
let dll_name_z = CString::new(lib_name).unwrap();
@@ -438,39 +359,3 @@ impl<'a> LlvmArchiveBuilder<'a> {
438359
fn string_to_io_error(s: String) -> io::Error {
439360
io::Error::new(io::ErrorKind::Other, format!("bad archive: {s}"))
440361
}
441-
442-
fn find_binutils_dlltool(sess: &Session) -> OsString {
443-
assert!(sess.target.options.is_like_windows && !sess.target.options.is_like_msvc);
444-
if let Some(dlltool_path) = &sess.opts.cg.dlltool {
445-
return dlltool_path.clone().into_os_string();
446-
}
447-
448-
let tool_name: OsString = if sess.host.options.is_like_windows {
449-
// If we're compiling on Windows, always use "dlltool.exe".
450-
"dlltool.exe"
451-
} else {
452-
// On other platforms, use the architecture-specific name.
453-
match sess.target.arch.as_ref() {
454-
"x86_64" => "x86_64-w64-mingw32-dlltool",
455-
"x86" => "i686-w64-mingw32-dlltool",
456-
"aarch64" => "aarch64-w64-mingw32-dlltool",
457-
458-
// For non-standard architectures (e.g., aarch32) fallback to "dlltool".
459-
_ => "dlltool",
460-
}
461-
}
462-
.into();
463-
464-
// NOTE: it's not clear how useful it is to explicitly search PATH.
465-
for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) {
466-
let full_path = dir.join(&tool_name);
467-
if full_path.is_file() {
468-
return full_path.into_os_string();
469-
}
470-
}
471-
472-
// The user didn't specify the location of the dlltool binary, and we weren't able
473-
// to find the appropriate one on the PATH. Just return the name of the tool
474-
// and let the invocation fail with a hopefully useful error message.
475-
tool_name
476-
}

compiler/rustc_codegen_llvm/src/errors.rs

-23
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use std::borrow::Cow;
21
use std::ffi::CString;
32
use std::path::Path;
43

@@ -70,28 +69,6 @@ pub(crate) struct InvalidMinimumAlignmentTooLarge {
7069
#[diag(codegen_llvm_sanitizer_memtag_requires_mte)]
7170
pub(crate) struct SanitizerMemtagRequiresMte;
7271

73-
#[derive(Diagnostic)]
74-
#[diag(codegen_llvm_error_writing_def_file)]
75-
pub(crate) struct ErrorWritingDEFFile {
76-
pub error: std::io::Error,
77-
}
78-
79-
#[derive(Diagnostic)]
80-
#[diag(codegen_llvm_error_calling_dlltool)]
81-
pub(crate) struct ErrorCallingDllTool<'a> {
82-
pub dlltool_path: Cow<'a, str>,
83-
pub error: std::io::Error,
84-
}
85-
86-
#[derive(Diagnostic)]
87-
#[diag(codegen_llvm_dlltool_fail_import_library)]
88-
pub(crate) struct DlltoolFailImportLibrary<'a> {
89-
pub dlltool_path: Cow<'a, str>,
90-
pub dlltool_args: String,
91-
pub stdout: Cow<'a, str>,
92-
pub stderr: Cow<'a, str>,
93-
}
94-
9572
#[derive(Diagnostic)]
9673
#[diag(codegen_llvm_dynamic_linking_with_lto)]
9774
#[note]

compiler/rustc_codegen_ssa/messages.ftl

+11
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,19 @@ codegen_ssa_copy_path_buf = unable to copy {$source_file} to {$output_path}: {$e
2525
2626
codegen_ssa_create_temp_dir = couldn't create a temp dir: {$error}
2727
28+
codegen_ssa_dlltool_fail_import_library =
29+
Dlltool could not create import library with {$dlltool_path} {$dlltool_args}:
30+
{$stdout}
31+
{$stderr}
32+
33+
codegen_ssa_error_calling_dlltool =
34+
Error calling dlltool '{$dlltool_path}': {$error}
35+
2836
codegen_ssa_error_creating_remark_dir = failed to create remark directory: {$error}
2937
38+
codegen_ssa_error_writing_def_file =
39+
Error writing .DEF file: {$error}
40+
3041
codegen_ssa_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
3142
3243
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

+127
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,14 @@ use object::read::archive::ArchiveFile;
1111
use object::read::macho::FatArch;
1212
use tempfile::Builder as TempFileBuilder;
1313

14+
use std::env;
1415
use std::error::Error;
16+
use std::ffi::OsString;
1517
use std::fs::{self, File};
1618
use std::io::{self, Write};
1719
use std::path::{Path, PathBuf};
1820

21+
use crate::errors::{DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorWritingDEFFile};
1922
// Re-exporting for rustc_codegen_llvm::back::archive
2023
pub use crate::errors::{ArchiveBuildFailure, ExtractBundledLibsError, UnknownArchiveKind};
2124

@@ -72,6 +75,130 @@ pub trait ArchiveBuilderBuilder {
7275
}
7376
}
7477

78+
pub fn create_mingw_dll_import_lib(
79+
sess: &Session,
80+
lib_name: &str,
81+
import_name_and_ordinal_vector: Vec<(String, Option<u16>)>,
82+
output_path: &Path,
83+
) {
84+
let def_file_path = output_path.with_extension("def");
85+
86+
let def_file_content = format!(
87+
"EXPORTS\n{}",
88+
import_name_and_ordinal_vector
89+
.into_iter()
90+
.map(|(name, ordinal)| {
91+
match ordinal {
92+
Some(n) => format!("{name} @{n} NONAME"),
93+
None => name,
94+
}
95+
})
96+
.collect::<Vec<String>>()
97+
.join("\n")
98+
);
99+
100+
match std::fs::write(&def_file_path, def_file_content) {
101+
Ok(_) => {}
102+
Err(e) => {
103+
sess.dcx().emit_fatal(ErrorWritingDEFFile { error: e });
104+
}
105+
};
106+
107+
// --no-leading-underscore: For the `import_name_type` feature to work, we need to be
108+
// able to control the *exact* spelling of each of the symbols that are being imported:
109+
// hence we don't want `dlltool` adding leading underscores automatically.
110+
let dlltool = find_binutils_dlltool(sess);
111+
let temp_prefix = {
112+
let mut path = PathBuf::from(&output_path);
113+
path.pop();
114+
path.push(lib_name);
115+
path
116+
};
117+
// dlltool target architecture args from:
118+
// https://github.com/llvm/llvm-project-release-prs/blob/llvmorg-15.0.6/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp#L69
119+
let (dlltool_target_arch, dlltool_target_bitness) = match sess.target.arch.as_ref() {
120+
"x86_64" => ("i386:x86-64", "--64"),
121+
"x86" => ("i386", "--32"),
122+
"aarch64" => ("arm64", "--64"),
123+
"arm" => ("arm", "--32"),
124+
_ => panic!("unsupported arch {}", sess.target.arch),
125+
};
126+
let mut dlltool_cmd = std::process::Command::new(&dlltool);
127+
dlltool_cmd
128+
.arg("-d")
129+
.arg(def_file_path)
130+
.arg("-D")
131+
.arg(lib_name)
132+
.arg("-l")
133+
.arg(&output_path)
134+
.arg("-m")
135+
.arg(dlltool_target_arch)
136+
.arg("-f")
137+
.arg(dlltool_target_bitness)
138+
.arg("--no-leading-underscore")
139+
.arg("--temp-prefix")
140+
.arg(temp_prefix);
141+
142+
match dlltool_cmd.output() {
143+
Err(e) => {
144+
sess.dcx().emit_fatal(ErrorCallingDllTool {
145+
dlltool_path: dlltool.to_string_lossy(),
146+
error: e,
147+
});
148+
}
149+
// dlltool returns '0' on failure, so check for error output instead.
150+
Ok(output) if !output.stderr.is_empty() => {
151+
sess.dcx().emit_fatal(DlltoolFailImportLibrary {
152+
dlltool_path: dlltool.to_string_lossy(),
153+
dlltool_args: dlltool_cmd
154+
.get_args()
155+
.map(|arg| arg.to_string_lossy())
156+
.collect::<Vec<_>>()
157+
.join(" "),
158+
stdout: String::from_utf8_lossy(&output.stdout),
159+
stderr: String::from_utf8_lossy(&output.stderr),
160+
})
161+
}
162+
_ => {}
163+
}
164+
}
165+
166+
fn find_binutils_dlltool(sess: &Session) -> OsString {
167+
assert!(sess.target.options.is_like_windows && !sess.target.options.is_like_msvc);
168+
if let Some(dlltool_path) = &sess.opts.cg.dlltool {
169+
return dlltool_path.clone().into_os_string();
170+
}
171+
172+
let tool_name: OsString = if sess.host.options.is_like_windows {
173+
// If we're compiling on Windows, always use "dlltool.exe".
174+
"dlltool.exe"
175+
} else {
176+
// On other platforms, use the architecture-specific name.
177+
match sess.target.arch.as_ref() {
178+
"x86_64" => "x86_64-w64-mingw32-dlltool",
179+
"x86" => "i686-w64-mingw32-dlltool",
180+
"aarch64" => "aarch64-w64-mingw32-dlltool",
181+
182+
// For non-standard architectures (e.g., aarch32) fallback to "dlltool".
183+
_ => "dlltool",
184+
}
185+
}
186+
.into();
187+
188+
// NOTE: it's not clear how useful it is to explicitly search PATH.
189+
for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) {
190+
let full_path = dir.join(&tool_name);
191+
if full_path.is_file() {
192+
return full_path.into_os_string();
193+
}
194+
}
195+
196+
// The user didn't specify the location of the dlltool binary, and we weren't able
197+
// to find the appropriate one on the PATH. Just return the name of the tool
198+
// and let the invocation fail with a hopefully useful error message.
199+
tool_name
200+
}
201+
75202
pub trait ArchiveBuilder {
76203
fn add_file(&mut self, path: &Path);
77204

0 commit comments

Comments
 (0)