Skip to content

Commit d12b0e7

Browse files
committed
Make dlltool version coexist with LLVM one
1 parent e5f5895 commit d12b0e7

File tree

1 file changed

+119
-36
lines changed

1 file changed

+119
-36
lines changed

compiler/rustc_codegen_llvm/src/back/archive.rs

+119-36
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
//! A helper class for dealing with static archives
22
3-
use std::ffi::{CStr, CString};
3+
use std::env;
4+
use std::ffi::{CStr, CString, OsString};
45
use std::io;
56
use std::mem;
67
use std::path::{Path, PathBuf};
78
use std::ptr;
89
use std::str;
910

1011
use crate::llvm::archive_ro::{ArchiveRO, Child};
11-
use crate::llvm::{self, ArchiveKind, LLVMMachineType};
12+
use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};
1213
use rustc_codegen_ssa::back::archive::ArchiveBuilder;
1314
use rustc_data_structures::temp_dir::MaybeTempDir;
1415
use rustc_middle::middle::cstore::{DllCallingConvention, DllImport};
@@ -54,7 +55,6 @@ fn archive_config<'a>(sess: &'a Session, output: &Path, input: Option<&Path>) ->
5455
ArchiveConfig { sess, dst: output.to_path_buf(), src: input.map(|p| p.to_path_buf()) }
5556
}
5657

57-
#[allow(dead_code)]
5858
/// Map machine type strings to values of LLVM's MachineTypes enum.
5959
fn llvm_machine_type(cpu: &str) -> LLVMMachineType {
6060
match cpu {
@@ -153,47 +153,107 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
153153
dll_imports: &[DllImport],
154154
tmpdir: &MaybeTempDir,
155155
) {
156-
let mut def_file_path = tmpdir.as_ref().to_path_buf();
157-
def_file_path.push(format!("{}_imports", lib_name));
158-
def_file_path.with_extension("def");
159-
let mut output_path: PathBuf = tmpdir.as_ref().to_path_buf();
160-
output_path.push(format!("{}_imports", lib_name));
161-
output_path.with_extension("dll.a");
162-
163-
let import_name_vector: Vec<String> = dll_imports
156+
let output_path = {
157+
let mut output_path: PathBuf = tmpdir.as_ref().to_path_buf();
158+
output_path.push(format!("{}_imports", lib_name));
159+
output_path.with_extension("lib")
160+
};
161+
162+
// BFD doesn't work properly with short imports
163+
let mingw_gnu_toolchain = self.config.sess.target.llvm_target.ends_with("pc-windows-gnu");
164+
165+
// All import names are Rust identifiers and therefore cannot contain \0 characters.
166+
// FIXME: when support for #[link_name] implemented, ensure that import.name values don't
167+
// have any \0 characters
168+
let import_name_vector: Vec<CString> = dll_imports
164169
.iter()
165170
.map(|import: &DllImport| {
166171
if self.config.sess.target.arch == "x86" {
167-
LlvmArchiveBuilder::i686_decorated_name(import, true).into_string().unwrap()
172+
LlvmArchiveBuilder::i686_decorated_name(import, mingw_gnu_toolchain)
168173
} else {
169-
import.name.to_string()
174+
CString::new(import.name.to_string()).unwrap()
170175
}
171176
})
172177
.collect();
173178

174-
let def_file_content = format!("EXPORTS\n{}", &import_name_vector.join("\n"));
175-
std::fs::write(&def_file_path, &def_file_content).unwrap();
176-
std::fs::copy(&def_file_path, "d:/imports.def").unwrap();
177-
178-
let result = std::process::Command::new("dlltool")
179-
.args([
180-
"-d",
181-
def_file_path.to_str().unwrap(),
182-
"-D",
183-
lib_name,
184-
"-l",
185-
output_path.to_str().unwrap(),
186-
])
187-
.status();
188-
189-
if let Err(e) = result {
190-
self.config.sess.fatal(&format!(
191-
"Error creating import library for {}: {}",
192-
lib_name,
193-
e.to_string()
194-
));
195-
}
196-
std::fs::copy(&output_path, "d:/imports.dll.a").unwrap();
179+
if mingw_gnu_toolchain {
180+
let mut def_file_path = tmpdir.as_ref().to_path_buf();
181+
def_file_path.push(format!("{}_imports", lib_name));
182+
def_file_path.with_extension("def");
183+
184+
let def_file_content = format!(
185+
"EXPORTS\n{}",
186+
import_name_vector
187+
.iter()
188+
.map(|cstring| cstring.to_str().unwrap())
189+
.intersperse("\n")
190+
.collect::<String>()
191+
);
192+
std::fs::write(&def_file_path, def_file_content).unwrap();
193+
194+
let dlltool = find_dlltool(self.config.sess);
195+
let result = std::process::Command::new(dlltool)
196+
.args([
197+
"-d",
198+
def_file_path.to_str().unwrap(),
199+
"-D",
200+
lib_name,
201+
"-l",
202+
output_path.to_str().unwrap(),
203+
])
204+
.output();
205+
206+
match result {
207+
Err(e) => {
208+
self.config.sess.fatal(&format!("Error calling dlltool: {}", e.to_string()))
209+
}
210+
Ok(output) if !output.status.success() => self.config.sess.fatal(&format!(
211+
"Dlltool could not create import library: {}\n{}",
212+
String::from_utf8_lossy(&output.stdout),
213+
String::from_utf8_lossy(&output.stderr)
214+
)),
215+
_ => {}
216+
}
217+
} else {
218+
// we've checked for \0 characters in the library name already
219+
let dll_name_z = CString::new(lib_name).unwrap();
220+
let output_path_z = rustc_fs_util::path_to_c_string(&output_path);
221+
222+
tracing::trace!("invoking LLVMRustWriteImportLibrary");
223+
tracing::trace!(" dll_name {:#?}", dll_name_z);
224+
tracing::trace!(" output_path {}", output_path.display());
225+
tracing::trace!(
226+
" import names: {}",
227+
dll_imports
228+
.iter()
229+
.map(|import| import.name.to_string())
230+
.collect::<Vec<_>>()
231+
.join(", "),
232+
);
233+
234+
let ffi_exports: Vec<LLVMRustCOFFShortExport> = import_name_vector
235+
.iter()
236+
.map(|name_z| LLVMRustCOFFShortExport::from_name(name_z.as_ptr()))
237+
.collect();
238+
let result = unsafe {
239+
crate::llvm::LLVMRustWriteImportLibrary(
240+
dll_name_z.as_ptr(),
241+
output_path_z.as_ptr(),
242+
ffi_exports.as_ptr(),
243+
ffi_exports.len(),
244+
llvm_machine_type(&self.config.sess.target.arch) as u16,
245+
!self.config.sess.target.is_like_msvc,
246+
)
247+
};
248+
249+
if result == crate::llvm::LLVMRustResult::Failure {
250+
self.config.sess.fatal(&format!(
251+
"Error creating import library for {}: {}",
252+
lib_name,
253+
llvm::last_error().unwrap_or("unknown LLVM error".to_string())
254+
));
255+
}
256+
};
197257

198258
self.add_archive(&output_path, |_| false).unwrap_or_else(|e| {
199259
self.config.sess.fatal(&format!(
@@ -343,3 +403,26 @@ impl<'a> LlvmArchiveBuilder<'a> {
343403
fn string_to_io_error(s: String) -> io::Error {
344404
io::Error::new(io::ErrorKind::Other, format!("bad archive: {}", s))
345405
}
406+
407+
fn find_dlltool(sess: &Session) -> OsString {
408+
// When cross-compiling first try binary prefixed with target triple
409+
if sess.host.llvm_target != sess.target.llvm_target {
410+
let prefixed_dlltool = if sess.target.arch == "x86" {
411+
"i686-w64-mingw32-dlltool"
412+
} else {
413+
"x86_64-w64-mingw32-dlltool"
414+
};
415+
let prefixed_dlltool = if cfg!(windows) {
416+
[prefixed_dlltool, "exe"].concat()
417+
} else {
418+
prefixed_dlltool.to_string()
419+
};
420+
for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) {
421+
let full_path = dir.join(&prefixed_dlltool);
422+
if full_path.is_file() {
423+
return full_path.into_os_string();
424+
}
425+
}
426+
}
427+
OsString::from("dlltool")
428+
}

0 commit comments

Comments
 (0)