Auto merge of #108355 - dpaoliello:dlltoolm, r=michaelwoerister

Fix cross-compiling with dlltool for raw-dylib

Fix for #103939

Issue Details:
When attempting to cross-compile using the `raw-dylib` feature and the GNU toolchain, rustc would attempt to find a cross-compiling version of dlltool (e.g., `i686-w64-mingw32-dlltool`). The has two issues 1) on Windows dlltool is always `dlltool` (no cross-compiling named versions exist) and 2) it only supported compiling to i686 and x86_64 resulting in ARM 32 and 64 compiling as x86_64.

Fix Details:
* On Windows always use the normal `dlltool` binary.
* Add the ARM64 cross-compiling dlltool name (support for this is coming: https://sourceware.org/bugzilla/show_bug.cgi?id=29964)
* Provide the `-m` argument to dlltool to indicate the target machine type.

(This is the first of two PRs to fix the remaining issues for the `raw-dylib` feature (#58713) that is blocking stabilization (#104218))
This commit is contained in:
bors 2023-03-23 09:51:32 +00:00
commit 9a6b0c3326
9 changed files with 87 additions and 14 deletions

View File

@ -189,6 +189,15 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
path.push(lib_name);
path
};
// dlltool target architecture args from:
// https://github.com/llvm/llvm-project-release-prs/blob/llvmorg-15.0.6/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp#L69
let (dlltool_target_arch, dlltool_target_bitness) = match sess.target.arch.as_ref() {
"x86_64" => ("i386:x86-64", "--64"),
"x86" => ("i386", "--32"),
"aarch64" => ("arm64", "--64"),
"arm" => ("arm", "--32"),
_ => panic!("unsupported arch {}", sess.target.arch),
};
let result = std::process::Command::new(dlltool)
.args([
"-d",
@ -197,6 +206,10 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
lib_name,
"-l",
output_path.to_str().unwrap(),
"-m",
dlltool_target_arch,
"-f",
dlltool_target_bitness,
"--no-leading-underscore",
"--temp-prefix",
temp_prefix.to_str().unwrap(),
@ -422,24 +435,22 @@ fn find_binutils_dlltool(sess: &Session) -> OsString {
return dlltool_path.clone().into_os_string();
}
let mut tool_name: OsString = if sess.host.arch != sess.target.arch {
// We are cross-compiling, so we need the tool with the prefix matching our target
if sess.target.arch == "x86" {
"i686-w64-mingw32-dlltool"
} else {
"x86_64-w64-mingw32-dlltool"
}
let tool_name: OsString = if sess.host.options.is_like_windows {
// If we're compiling on Windows, always use "dlltool.exe".
"dlltool.exe"
} else {
// We are not cross-compiling, so we just want `dlltool`
"dlltool"
// On other platforms, use the architecture-specific name.
match sess.target.arch.as_ref() {
"x86_64" => "x86_64-w64-mingw32-dlltool",
"x86" => "i686-w64-mingw32-dlltool",
"aarch64" => "aarch64-w64-mingw32-dlltool",
// For non-standard architectures (e.g., aarch32) fallback to "dlltool".
_ => "dlltool",
}
}
.into();
if sess.host.options.is_like_windows {
// If we're compiling on Windows, add the .exe suffix
tool_name.push(".exe");
}
// NOTE: it's not clear how useful it is to explicitly search PATH.
for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) {
let full_path = dir.join(&tool_name);

View File

@ -16,6 +16,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
zlib1g-dev \
lib32z1-dev \
xz-utils \
mingw-w64 \
&& rm -rf /var/lib/apt/lists/*

View File

@ -22,6 +22,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
zlib1g-dev \
xz-utils \
nodejs \
mingw-w64 \
&& rm -rf /var/lib/apt/lists/*
COPY scripts/sccache.sh /scripts/

View File

@ -23,6 +23,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
zlib1g-dev \
xz-utils \
nodejs \
mingw-w64 \
&& rm -rf /var/lib/apt/lists/*
# Install powershell (universal package) so we can test x.ps1 on Linux

View File

@ -25,6 +25,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
zlib1g-dev \
xz-utils \
nodejs \
mingw-w64 \
&& rm -rf /var/lib/apt/lists/*
# Install powershell (universal package) so we can test x.ps1 on Linux

View File

@ -16,6 +16,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
libssl-dev \
pkg-config \
xz-utils \
mingw-w64 \
&& rm -rf /var/lib/apt/lists/*
COPY scripts/sccache.sh /scripts/

View File

@ -964,6 +964,19 @@ pub fn make_test_description<R: Read>(
.join(if config.host.contains("windows") { "rust-lld.exe" } else { "rust-lld" })
.exists();
fn is_on_path(file: &'static str) -> impl Fn() -> bool {
move || env::split_paths(&env::var_os("PATH").unwrap()).any(|dir| dir.join(file).is_file())
}
// On Windows, dlltool.exe is used for all architectures.
#[cfg(windows)]
let (has_i686_dlltool, has_x86_64_dlltool) =
(is_on_path("dlltool.exe"), is_on_path("dlltool.exe"));
// For non-Windows, there are architecture specific dlltool binaries.
#[cfg(not(windows))]
let (has_i686_dlltool, has_x86_64_dlltool) =
(is_on_path("i686-w64-mingw32-dlltool"), is_on_path("x86_64-w64-mingw32-dlltool"));
iter_header(path, src, &mut |revision, ln| {
if revision.is_some() && revision != cfg {
return;
@ -1031,6 +1044,8 @@ pub fn make_test_description<R: Read>(
reason!(config.debugger == Some(Debugger::Gdb) && ignore_gdb(config, ln));
reason!(config.debugger == Some(Debugger::Lldb) && ignore_lldb(config, ln));
reason!(!has_rust_lld && config.parse_name_directive(ln, "needs-rust-lld"));
reason!(config.parse_name_directive(ln, "needs-i686-dlltool") && !has_i686_dlltool());
reason!(config.parse_name_directive(ln, "needs-x86_64-dlltool") && !has_x86_64_dlltool());
should_fail |= config.parse_name_directive(ln, "should-fail");
});

View File

@ -0,0 +1,22 @@
# Tests that raw-dylib cross compilation works correctly
# only-gnu
# needs-i686-dlltool
# needs-x86_64-dlltool
# i686 dlltool.exe can't product x64 binaries.
# ignore-i686-pc-windows-gnu
include ../../run-make-fulldeps/tools.mk
all:
# Build as x86 and make sure that we have x86 objects only.
$(RUSTC) --crate-type lib --crate-name i686_raw_dylib_test --target i686-pc-windows-gnu lib.rs
"$(LLVM_BIN_DIR)"/llvm-objdump -a $(TMPDIR)/libi686_raw_dylib_test.rlib > $(TMPDIR)/i686.objdump.txt
$(CGREP) "file format coff-i386" < $(TMPDIR)/i686.objdump.txt
$(CGREP) -v "file format coff-x86-64" < $(TMPDIR)/i686.objdump.txt
# Build as x64 and make sure that we have x64 objects only.
$(RUSTC) --crate-type lib --crate-name x64_raw_dylib_test --target x86_64-pc-windows-gnu lib.rs
"$(LLVM_BIN_DIR)"/llvm-objdump -a $(TMPDIR)/libx64_raw_dylib_test.rlib > $(TMPDIR)/x64.objdump.txt
$(CGREP) "file format coff-x86-64" < $(TMPDIR)/x64.objdump.txt
$(CGREP) -v "file format coff-i386" < $(TMPDIR)/x64.objdump.txt

View File

@ -0,0 +1,20 @@
#![feature(raw_dylib)]
#![feature(no_core, lang_items)]
#![no_std]
#![no_core]
#![crate_type = "lib"]
// This is needed because of #![no_core]:
#[lang = "sized"]
trait Sized {}
#[link(name = "extern_1", kind = "raw-dylib")]
extern {
fn extern_fn();
}
pub fn extern_fn_caller() {
unsafe {
extern_fn();
}
}