1
1
//! A helper class for dealing with static archives
2
2
3
- use std::ffi::{c_char, c_void, CStr, CString, OsString };
3
+ use std::ffi::{c_char, c_void, CStr, CString};
4
4
use std::path::{Path, PathBuf};
5
- use std::{env, io, mem, ptr, str};
5
+ use std::{io, mem, ptr, str};
6
6
7
7
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,
10
11
};
11
- use rustc_session::cstore::DllImport ;
12
+ use rustc_codegen_ssa::common ;
12
13
use rustc_session::Session;
13
14
use tracing::trace;
14
15
15
- use crate::common;
16
- use crate::errors::{
17
- DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorCreatingImportLibrary, ErrorWritingDEFFile,
18
- };
16
+ use crate::errors::ErrorCreatingImportLibrary;
19
17
use crate::llvm::archive_ro::{ArchiveRO, Child};
20
18
use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};
21
19
@@ -121,116 +119,21 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
121
119
&self,
122
120
sess: &Session,
123
121
lib_name: &str,
124
- dll_imports: &[DllImport],
125
- tmpdir: &Path,
126
- is_direct_dependency: bool,
127
- ) -> PathBuf {
128
- let name_suffix = if is_direct_dependency { "_imports" } else { "_imports_indirect" };
129
- let output_path = tmpdir.join(format!("{lib_name}{name_suffix}.lib"));
130
-
131
- let target = &sess.target;
132
- let mingw_gnu_toolchain = common::is_mingw_gnu_toolchain(target);
133
-
134
- let import_name_and_ordinal_vector: Vec<(String, Option<u16>)> = dll_imports
135
- .iter()
136
- .map(|import: &DllImport| {
137
- if sess.target.arch == "x86" {
138
- (
139
- common::i686_decorated_name(import, mingw_gnu_toolchain, false),
140
- import.ordinal(),
141
- )
142
- } else {
143
- (import.name.to_string(), import.ordinal())
144
- }
145
- })
146
- .collect();
147
-
148
- if mingw_gnu_toolchain {
122
+ import_name_and_ordinal_vector: Vec<(String, Option<u16>)>,
123
+ output_path: &Path,
124
+ ) {
125
+ if common::is_mingw_gnu_toolchain(&sess.target) {
149
126
// The binutils linker used on -windows-gnu targets cannot read the import
150
127
// libraries generated by LLVM: in our attempts, the linker produced an .EXE
151
128
// that loaded but crashed with an AV upon calling one of the imported
152
129
// functions. Therefore, use binutils to create the import library instead,
153
130
// by writing a .DEF file to the temp dir and calling binutils's dlltool.
154
- let def_file_path = tmpdir.join(format!("{lib_name}{name_suffix}.def"));
155
-
156
- let def_file_content = format!(
157
- "EXPORTS\n{}",
158
- import_name_and_ordinal_vector
159
- .into_iter()
160
- .map(|(name, ordinal)| {
161
- match ordinal {
162
- Some(n) => format!("{name} @{n} NONAME"),
163
- None => name,
164
- }
165
- })
166
- .collect::<Vec<String>>()
167
- .join("\n")
131
+ create_mingw_dll_import_lib(
132
+ sess,
133
+ lib_name,
134
+ import_name_and_ordinal_vector,
135
+ output_path,
168
136
);
169
-
170
- match std::fs::write(&def_file_path, def_file_content) {
171
- Ok(_) => {}
172
- Err(e) => {
173
- sess.dcx().emit_fatal(ErrorWritingDEFFile { error: e });
174
- }
175
- };
176
-
177
- // --no-leading-underscore: For the `import_name_type` feature to work, we need to be
178
- // able to control the *exact* spelling of each of the symbols that are being imported:
179
- // hence we don't want `dlltool` adding leading underscores automatically.
180
- let dlltool = find_binutils_dlltool(sess);
181
- let temp_prefix = {
182
- let mut path = PathBuf::from(&output_path);
183
- path.pop();
184
- path.push(lib_name);
185
- path
186
- };
187
- // dlltool target architecture args from:
188
- // https://github.com/llvm/llvm-project-release-prs/blob/llvmorg-15.0.6/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp#L69
189
- let (dlltool_target_arch, dlltool_target_bitness) = match sess.target.arch.as_ref() {
190
- "x86_64" => ("i386:x86-64", "--64"),
191
- "x86" => ("i386", "--32"),
192
- "aarch64" => ("arm64", "--64"),
193
- "arm" => ("arm", "--32"),
194
- _ => panic!("unsupported arch {}", sess.target.arch),
195
- };
196
- let mut dlltool_cmd = std::process::Command::new(&dlltool);
197
- dlltool_cmd
198
- .arg("-d")
199
- .arg(def_file_path)
200
- .arg("-D")
201
- .arg(lib_name)
202
- .arg("-l")
203
- .arg(&output_path)
204
- .arg("-m")
205
- .arg(dlltool_target_arch)
206
- .arg("-f")
207
- .arg(dlltool_target_bitness)
208
- .arg("--no-leading-underscore")
209
- .arg("--temp-prefix")
210
- .arg(temp_prefix);
211
-
212
- match dlltool_cmd.output() {
213
- Err(e) => {
214
- sess.dcx().emit_fatal(ErrorCallingDllTool {
215
- dlltool_path: dlltool.to_string_lossy(),
216
- error: e,
217
- });
218
- }
219
- // dlltool returns '0' on failure, so check for error output instead.
220
- Ok(output) if !output.stderr.is_empty() => {
221
- sess.dcx().emit_fatal(DlltoolFailImportLibrary {
222
- dlltool_path: dlltool.to_string_lossy(),
223
- dlltool_args: dlltool_cmd
224
- .get_args()
225
- .map(|arg| arg.to_string_lossy())
226
- .collect::<Vec<_>>()
227
- .join(" "),
228
- stdout: String::from_utf8_lossy(&output.stdout),
229
- stderr: String::from_utf8_lossy(&output.stderr),
230
- })
231
- }
232
- _ => {}
233
- }
234
137
} else {
235
138
// we've checked for \0 characters in the library name already
236
139
let dll_name_z = CString::new(lib_name).unwrap();
@@ -242,9 +145,9 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
242
145
trace!(" output_path {}", output_path.display());
243
146
trace!(
244
147
" import names: {}",
245
- dll_imports
148
+ import_name_and_ordinal_vector
246
149
.iter()
247
- .map(|import| import. name.to_string ())
150
+ .map(|(name, _ordinal)| name.clone ())
248
151
.collect::<Vec<_>>()
249
152
.join(", "),
250
153
);
@@ -281,9 +184,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
281
184
error: llvm::last_error().unwrap_or("unknown LLVM error".to_string()),
282
185
});
283
186
}
284
- };
285
-
286
- output_path
187
+ }
287
188
}
288
189
}
289
190
@@ -457,39 +358,3 @@ impl<'a> LlvmArchiveBuilder<'a> {
457
358
fn string_to_io_error(s: String) -> io::Error {
458
359
io::Error::new(io::ErrorKind::Other, format!("bad archive: {s}"))
459
360
}
460
-
461
- fn find_binutils_dlltool(sess: &Session) -> OsString {
462
- assert!(sess.target.options.is_like_windows && !sess.target.options.is_like_msvc);
463
- if let Some(dlltool_path) = &sess.opts.cg.dlltool {
464
- return dlltool_path.clone().into_os_string();
465
- }
466
-
467
- let tool_name: OsString = if sess.host.options.is_like_windows {
468
- // If we're compiling on Windows, always use "dlltool.exe".
469
- "dlltool.exe"
470
- } else {
471
- // On other platforms, use the architecture-specific name.
472
- match sess.target.arch.as_ref() {
473
- "x86_64" => "x86_64-w64-mingw32-dlltool",
474
- "x86" => "i686-w64-mingw32-dlltool",
475
- "aarch64" => "aarch64-w64-mingw32-dlltool",
476
-
477
- // For non-standard architectures (e.g., aarch32) fallback to "dlltool".
478
- _ => "dlltool",
479
- }
480
- }
481
- .into();
482
-
483
- // NOTE: it's not clear how useful it is to explicitly search PATH.
484
- for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) {
485
- let full_path = dir.join(&tool_name);
486
- if full_path.is_file() {
487
- return full_path.into_os_string();
488
- }
489
- }
490
-
491
- // The user didn't specify the location of the dlltool binary, and we weren't able
492
- // to find the appropriate one on the PATH. Just return the name of the tool
493
- // and let the invocation fail with a hopefully useful error message.
494
- tool_name
495
- }
0 commit comments