Skip to content

Commit 216686b

Browse files
committed
Move mingw dlltool invocation to cg_ssa
1 parent 3c987cb commit 216686b

File tree

6 files changed

+172
-159
lines changed

6 files changed

+172
-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

+12-126
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
11
//! A helper class for dealing with static archives
22
3-
use std::ffi::{c_char, c_void, CStr, CString, OsString};
3+
use std::ffi::{c_char, c_void, CStr, CString};
44
use std::path::{Path, PathBuf};
5-
use std::{env, io, mem, ptr, str};
5+
use std::{io, mem, ptr, str};
66

77
use rustc_codegen_ssa::back::archive::{
8-
try_extract_macho_fat_archive, ArArchiveBuilder, ArchiveBuildFailure, ArchiveBuilder,
9-
ArchiveBuilderBuilder, ObjectReader, UnknownArchiveKind, DEFAULT_OBJECT_READER,
8+
create_mingw_dll_import_lib, try_extract_macho_fat_archive, ArArchiveBuilder,
9+
ArchiveBuildFailure, ArchiveBuilder, ArchiveBuilderBuilder, ObjectReader, UnknownArchiveKind,
10+
DEFAULT_OBJECT_READER,
1011
};
1112
use rustc_codegen_ssa::common;
1213
use rustc_session::Session;
1314
use tracing::trace;
1415

15-
use crate::errors::{
16-
DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorCreatingImportLibrary, ErrorWritingDEFFile,
17-
};
16+
use crate::errors::ErrorCreatingImportLibrary;
1817
use crate::llvm::archive_ro::{ArchiveRO, Child};
1918
use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};
2019

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

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

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

74-
#[derive(Diagnostic)]
75-
#[diag(codegen_llvm_error_writing_def_file)]
76-
pub(crate) struct ErrorWritingDEFFile {
77-
pub error: std::io::Error,
78-
}
79-
80-
#[derive(Diagnostic)]
81-
#[diag(codegen_llvm_error_calling_dlltool)]
82-
pub(crate) struct ErrorCallingDllTool<'a> {
83-
pub dlltool_path: Cow<'a, str>,
84-
pub error: std::io::Error,
85-
}
86-
87-
#[derive(Diagnostic)]
88-
#[diag(codegen_llvm_dlltool_fail_import_library)]
89-
pub(crate) struct DlltoolFailImportLibrary<'a> {
90-
pub dlltool_path: Cow<'a, str>,
91-
pub dlltool_args: String,
92-
pub stdout: Cow<'a, str>,
93-
pub stderr: Cow<'a, str>,
94-
}
95-
9673
#[derive(Diagnostic)]
9774
#[diag(codegen_llvm_dynamic_linking_with_lto)]
9875
#[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
@@ -1,4 +1,6 @@
1+
use std::env;
12
use std::error::Error;
3+
use std::ffi::OsString;
24
use std::fs::{self, File};
35
use std::io::{self, Write};
46
use std::path::{Path, PathBuf};
@@ -16,6 +18,7 @@ use tempfile::Builder as TempFileBuilder;
1618
use super::metadata::search_for_section;
1719
// Re-exporting for rustc_codegen_llvm::back::archive
1820
pub use crate::errors::{ArchiveBuildFailure, ExtractBundledLibsError, UnknownArchiveKind};
21+
use crate::errors::{DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorWritingDEFFile};
1922

2023
pub trait ArchiveBuilderBuilder {
2124
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a>;
@@ -70,6 +73,130 @@ pub trait ArchiveBuilderBuilder {
7073
}
7174
}
7275

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

0 commit comments

Comments
 (0)