diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index dd3268d7780c6..a570f2af0f0e5 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -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); diff --git a/src/ci/docker/host-x86_64/i686-gnu/Dockerfile b/src/ci/docker/host-x86_64/i686-gnu/Dockerfile index d9e58386256d3..b5abf6564a633 100644 --- a/src/ci/docker/host-x86_64/i686-gnu/Dockerfile +++ b/src/ci/docker/host-x86_64/i686-gnu/Dockerfile @@ -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/* diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14-stage1/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14-stage1/Dockerfile index b99a0886b4d9b..21dcf29b4a9f9 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14-stage1/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14-stage1/Dockerfile @@ -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/ diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile index dc8a4aac76873..cfb638e8b07aa 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile @@ -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 diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile index 5219247cc6f6c..fb5037e3b973d 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile @@ -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 diff --git a/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile index 5b9581f72a64e..fbec368c9ee55 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile @@ -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/ diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 22a0b1d13be16..5bc9d9afcb9d1 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -964,6 +964,19 @@ pub fn make_test_description( .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( 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"); }); diff --git a/tests/run-make/raw-dylib-cross-compilation/Makefile b/tests/run-make/raw-dylib-cross-compilation/Makefile new file mode 100644 index 0000000000000..2a714f3a11fea --- /dev/null +++ b/tests/run-make/raw-dylib-cross-compilation/Makefile @@ -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 diff --git a/tests/run-make/raw-dylib-cross-compilation/lib.rs b/tests/run-make/raw-dylib-cross-compilation/lib.rs new file mode 100644 index 0000000000000..51bf2ec6b6e11 --- /dev/null +++ b/tests/run-make/raw-dylib-cross-compilation/lib.rs @@ -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(); + } +}