From 60361f2ca34f24955aff729826971c43ec254cf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Sun, 6 Mar 2022 15:12:50 +0100 Subject: [PATCH] Add LLVM based mingw-w64 targets --- .../rustc_codegen_llvm/src/back/archive.rs | 6 ++- compiler/rustc_llvm/build.rs | 9 ++-- .../src/spec/aarch64_pc_windows_gnullvm.rs | 16 ++++++ compiler/rustc_target/src/spec/mod.rs | 4 ++ .../src/spec/windows_gnullvm_base.rs | 52 +++++++++++++++++++ .../src/spec/x86_64_pc_windows_gnullvm.rs | 19 +++++++ library/unwind/build.rs | 2 +- library/unwind/src/lib.rs | 5 ++ src/bootstrap/compile.rs | 5 +- src/bootstrap/dist.rs | 20 +++---- src/bootstrap/native.rs | 4 ++ src/doc/rustc/src/SUMMARY.md | 1 + src/doc/rustc/src/platform-support.md | 2 + .../platform-support/pc-windows-gnullvm.md | 48 +++++++++++++++++ 14 files changed, 175 insertions(+), 18 deletions(-) create mode 100644 compiler/rustc_target/src/spec/aarch64_pc_windows_gnullvm.rs create mode 100644 compiler/rustc_target/src/spec/windows_gnullvm_base.rs create mode 100644 compiler/rustc_target/src/spec/x86_64_pc_windows_gnullvm.rs create mode 100644 src/doc/rustc/src/platform-support/pc-windows-gnullvm.md diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index f814cc9304331..8f6438e85ad7f 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -152,8 +152,10 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { }; let target = &self.config.sess.target; - let mingw_gnu_toolchain = - target.vendor == "pc" && target.os == "windows" && target.env == "gnu"; + let mingw_gnu_toolchain = target.vendor == "pc" + && target.os == "windows" + && target.env == "gnu" + && target.abi.is_empty(); let import_name_and_ordinal_vector: Vec<(String, Option)> = dll_imports .iter() diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index ac758c15cca78..7729ec6bef4a7 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -324,9 +324,10 @@ fn main() { let stdcppname = if target.contains("openbsd") { if target.contains("sparc64") { "estdc++" } else { "c++" } - } else if target.contains("freebsd") { - "c++" - } else if target.contains("darwin") { + } else if target.contains("darwin") + || target.contains("freebsd") + || target.contains("windows-gnullvm") + { "c++" } else if target.contains("netbsd") && llvm_static_stdcpp.is_some() { // NetBSD uses a separate library when relocation is required @@ -365,7 +366,7 @@ fn main() { // Libstdc++ depends on pthread which Rust doesn't link on MinGW // since nothing else requires it. - if target.contains("windows-gnu") { + if target.ends_with("windows-gnu") { println!("cargo:rustc-link-lib=static:-bundle=pthread"); } } diff --git a/compiler/rustc_target/src/spec/aarch64_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/aarch64_pc_windows_gnullvm.rs new file mode 100644 index 0000000000000..59c6a95c2c5c2 --- /dev/null +++ b/compiler/rustc_target/src/spec/aarch64_pc_windows_gnullvm.rs @@ -0,0 +1,16 @@ +use crate::spec::Target; + +pub fn target() -> Target { + let mut base = super::windows_gnullvm_base::opts(); + base.max_atomic_width = Some(64); + base.features = "+neon,+fp-armv8".into(); + base.linker = Some("aarch64-w64-mingw32-clang".into()); + + Target { + llvm_target: "aarch64-pc-windows-gnu".into(), + pointer_width: 64, + data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128".into(), + arch: "aarch64".into(), + options: base, + } +} diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 965a3c109832b..832eeec3e8b27 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -82,6 +82,7 @@ mod uefi_msvc_base; mod vxworks_base; mod wasm_base; mod windows_gnu_base; +mod windows_gnullvm_base; mod windows_msvc_base; mod windows_uwp_gnu_base; mod windows_uwp_msvc_base; @@ -939,6 +940,9 @@ supported_targets! { ("i686-uwp-windows-gnu", i686_uwp_windows_gnu), ("x86_64-uwp-windows-gnu", x86_64_uwp_windows_gnu), + ("aarch64-pc-windows-gnullvm", aarch64_pc_windows_gnullvm), + ("x86_64-pc-windows-gnullvm", x86_64_pc_windows_gnullvm), + ("aarch64-pc-windows-msvc", aarch64_pc_windows_msvc), ("aarch64-uwp-windows-msvc", aarch64_uwp_windows_msvc), ("x86_64-pc-windows-msvc", x86_64_pc_windows_msvc), diff --git a/compiler/rustc_target/src/spec/windows_gnullvm_base.rs b/compiler/rustc_target/src/spec/windows_gnullvm_base.rs new file mode 100644 index 0000000000000..9f9f8be87184e --- /dev/null +++ b/compiler/rustc_target/src/spec/windows_gnullvm_base.rs @@ -0,0 +1,52 @@ +use crate::spec::{cvs, LinkArgs, LinkerFlavor, TargetOptions}; + +pub fn opts() -> TargetOptions { + let pre_link_args = LinkArgs::from([( + LinkerFlavor::Gcc, + vec![ + // We cannot use `-nodefaultlibs` because compiler-rt has to be passed + // as a path since it's not added to linker search path by the default. + // There were attemts to make it behave like libgcc (so one can just use -l) + // but LLVM maintainers rejected it: https://reviews.llvm.org/D51440 + "-nolibc".into(), + "--unwindlib=none".into(), + ], + )]); + let late_link_args = LinkArgs::from([( + LinkerFlavor::Gcc, + // Order of `late_link_args*` does not matter with LLD. + vec![ + "-lmingw32".into(), + "-lmingwex".into(), + "-lmsvcrt".into(), + "-lkernel32".into(), + "-luser32".into(), + ], + )]); + + TargetOptions { + os: "windows".into(), + env: "gnu".into(), + vendor: "pc".into(), + abi: "llvm".into(), + linker: Some("clang".into()), + dynamic_linking: true, + executables: true, + dll_prefix: "".into(), + dll_suffix: ".dll".into(), + exe_suffix: ".exe".into(), + families: cvs!["windows"], + is_like_windows: true, + allows_weak_linkage: false, + pre_link_args, + late_link_args, + abi_return_struct_as_int: true, + emit_debug_gdb_scripts: false, + requires_uwtable: true, + eh_frame_header: false, + no_default_libraries: false, + has_thread_local: true, + + ..Default::default() + } +} diff --git a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnullvm.rs new file mode 100644 index 0000000000000..b5ff63e0532fd --- /dev/null +++ b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnullvm.rs @@ -0,0 +1,19 @@ +use crate::spec::{LinkerFlavor, Target}; + +pub fn target() -> Target { + let mut base = super::windows_gnullvm_base::opts(); + base.cpu = "x86-64".into(); + let gcc_pre_link_args = base.pre_link_args.entry(LinkerFlavor::Gcc).or_default(); + gcc_pre_link_args.push("-m64".into()); + base.max_atomic_width = Some(64); + base.linker = Some("x86_64-w64-mingw32-clang".into()); + + Target { + llvm_target: "x86_64-pc-windows-gnu".into(), + pointer_width: 64, + data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + .into(), + arch: "x86_64".into(), + options: base, + } +} diff --git a/library/unwind/build.rs b/library/unwind/build.rs index 61d3f45ca6523..f88e6a924b5f0 100644 --- a/library/unwind/build.rs +++ b/library/unwind/build.rs @@ -36,7 +36,7 @@ fn main() { println!("cargo:rustc-link-lib=gcc_s"); } else if target.contains("dragonfly") { println!("cargo:rustc-link-lib=gcc_pic"); - } else if target.contains("pc-windows-gnu") { + } else if target.ends_with("pc-windows-gnu") { // This is handled in the target spec with late_link_args_[static|dynamic] } else if target.contains("uwp-windows-gnu") { println!("cargo:rustc-link-lib=unwind"); diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index a01b56004c456..c92a7d310f309 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -5,6 +5,7 @@ #![feature(nll)] #![feature(staged_api)] #![feature(c_unwind)] +#![feature(cfg_target_abi)] #![cfg_attr(not(target_env = "msvc"), feature(libc))] cfg_if::cfg_if! { @@ -85,3 +86,7 @@ extern "C" {} #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] #[link(name = "unwind", kind = "static", modifiers = "-bundle")] extern "C" {} + +#[cfg(all(target_os = "windows", target_env = "gnu", target_abi = "llvm"))] +#[link(name = "unwind", kind = "static", modifiers = "-bundle")] +extern "C" {} diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 53933e4cd7d20..7a8c7fee5f549 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -175,6 +175,7 @@ fn copy_third_party_objects( } if target == "x86_64-fortanix-unknown-sgx" + || target.contains("pc-windows-gnullvm") || builder.config.llvm_libunwind == LlvmLibunwind::InTree && (target.contains("linux") || target.contains("fuchsia")) { @@ -246,7 +247,7 @@ fn copy_self_contained_objects( DependencyType::TargetSelfContained, ); } - } else if target.contains("windows-gnu") { + } else if target.ends_with("windows-gnu") { for obj in ["crt2.o", "dllcrt2.o"].iter() { let src = compiler_file(builder, builder.cc(target), target, CLang::C, obj); let target = libdir_self_contained.join(obj); @@ -477,7 +478,7 @@ impl Step for StartupObjects { fn run(self, builder: &Builder<'_>) -> Vec<(PathBuf, DependencyType)> { let for_compiler = self.compiler; let target = self.target; - if !target.contains("windows-gnu") { + if !target.ends_with("windows-gnu") { return vec![]; } diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index d37a59426f895..6181a611ec315 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -285,7 +285,7 @@ impl Step for Mingw { /// without any extra installed software (e.g., we bundle gcc, libraries, etc). fn run(self, builder: &Builder<'_>) -> Option { let host = self.host; - if !host.contains("pc-windows-gnu") { + if !host.ends_with("pc-windows-gnu") { return None; } @@ -341,7 +341,7 @@ impl Step for Rustc { // anything requiring us to distribute a license, but it's likely the // install will *also* include the rust-mingw package, which also needs // licenses, so to be safe we just include it here in all MinGW packages. - if host.contains("pc-windows-gnu") { + if host.ends_with("pc-windows-gnu") { make_win_dist(tarball.image_dir(), &tmpdir(builder), host, builder); tarball.add_dir(builder.src.join("src/etc/third-party"), "share/doc"); } @@ -1352,7 +1352,7 @@ impl Step for Extended { tarballs.push(builder.ensure(Rustc { compiler: builder.compiler(stage, target) })); tarballs.push(builder.ensure(Std { compiler, target }).expect("missing std")); - if target.contains("windows-gnu") { + if target.ends_with("windows-gnu") { tarballs.push(builder.ensure(Mingw { host: target }).expect("missing mingw")); } @@ -1522,7 +1522,7 @@ impl Step for Extended { prepare(tool); } } - if target.contains("windows-gnu") { + if target.ends_with("windows-gnu") { prepare("rust-mingw"); } @@ -1711,7 +1711,7 @@ impl Step for Extended { .arg("-t") .arg(etc.join("msi/remove-duplicates.xsl")), ); - if target.contains("windows-gnu") { + if target.ends_with("windows-gnu") { builder.run( Command::new(&heat) .current_dir(&exe) @@ -1760,7 +1760,7 @@ impl Step for Extended { if built_tools.contains("miri") { cmd.arg("-dMiriDir=miri"); } - if target.contains("windows-gnu") { + if target.ends_with("windows-gnu") { cmd.arg("-dGccDir=rust-mingw"); } builder.run(&mut cmd); @@ -1787,7 +1787,7 @@ impl Step for Extended { } candle("AnalysisGroup.wxs".as_ref()); - if target.contains("windows-gnu") { + if target.ends_with("windows-gnu") { candle("GccGroup.wxs".as_ref()); } @@ -1829,7 +1829,7 @@ impl Step for Extended { cmd.arg("MiriGroup.wixobj"); } - if target.contains("windows-gnu") { + if target.ends_with("windows-gnu") { cmd.arg("GccGroup.wixobj"); } // ICE57 wrongly complains about the shortcuts @@ -1859,7 +1859,9 @@ fn add_env(builder: &Builder<'_>, cmd: &mut Command, target: TargetSelection) { .env("CFG_BUILD", target.triple) .env("CFG_CHANNEL", &builder.config.channel); - if target.contains("windows-gnu") { + if target.contains("windows-gnullvm") { + cmd.env("CFG_MINGW", "1").env("CFG_ABI", "LLVM"); + } else if target.contains("windows-gnu") { cmd.env("CFG_MINGW", "1").env("CFG_ABI", "GNU"); } else { cmd.env("CFG_MINGW", "0").env("CFG_ABI", "MSVC"); diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 64e25f803b27f..977b0e80f62d5 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -1372,6 +1372,10 @@ impl Step for Libunwind { cfg.define("__LIBUNWIND_IS_NATIVE_ONLY", None); cfg.define("NDEBUG", None); } + if self.target.contains("windows") { + cfg.define("_LIBUNWIND_HIDE_SYMBOLS", "1"); + cfg.define("_LIBUNWIND_IS_NATIVE_ONLY", "1"); + } } cc_cfg.compiler(builder.cc(self.target)); diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index df95325c83d5d..c2d44ac0e4dce 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -21,6 +21,7 @@ - [m68k-unknown-linux-gnu](platform-support/m68k-unknown-linux-gnu.md) - [mips64-openwrt-linux-musl](platform-support/mips64-openwrt-linux-musl.md) - [nvptx64-nvidia-cuda](platform-support/nvptx64-nvidia-cuda.md) + - [*-pc-windows-gnullvm](platform-support/pc-windows-gnullvm.md) - [*-unknown-openbsd](platform-support/openbsd.md) - [wasm64-unknown-unknown](platform-support/wasm64-unknown-unknown.md) - [x86_64-unknown-none](platform-support/x86_64-unknown-none.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 12ac575210aa3..ab98651a1ec3a 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -208,6 +208,7 @@ target | std | host | notes `aarch64-apple-ios-macabi` | ? | | Apple Catalyst on ARM64 `aarch64-apple-tvos` | * | | ARM64 tvOS [`aarch64-kmc-solid_asp3`](platform-support/kmc-solid.md) | ✓ | | ARM64 SOLID with TOPPERS/ASP3 +[`aarch64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ | `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD `aarch64-unknown-hermit` | ✓ | | ARM64 HermitCore `aarch64-unknown-uefi` | * | | ARM64 UEFI @@ -288,6 +289,7 @@ target | std | host | notes [`wasm64-unknown-unknown`](platform-support/wasm64-unknown-unknown.md) | ? | | WebAssembly `x86_64-apple-ios-macabi` | ✓ | | Apple Catalyst on x86_64 `x86_64-apple-tvos` | * | | x86 64-bit tvOS +[`x86_64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ | `x86_64-pc-windows-msvc` | * | | 64-bit Windows XP support `x86_64-sun-solaris` | ? | | Deprecated target for 64-bit Solaris 10/11, illumos `x86_64-unknown-dragonfly` | ✓ | ✓ | 64-bit DragonFlyBSD diff --git a/src/doc/rustc/src/platform-support/pc-windows-gnullvm.md b/src/doc/rustc/src/platform-support/pc-windows-gnullvm.md new file mode 100644 index 0000000000000..96ae065b31b0b --- /dev/null +++ b/src/doc/rustc/src/platform-support/pc-windows-gnullvm.md @@ -0,0 +1,48 @@ +# \*-pc-windows-gnullvm + +**Tier: 3** + +Windows targets similar to `*-pc-windows-gnu` but using UCRT as the runtime and various LLVM tools/libraries instead of GCC/Binutils. + +Target triples avaiable so far: +- `aarch64-pc-windows-gnullvm` +- `x86_64-pc-windows-gnullvm` + +## Target maintainers + +- [@mati865](https://github.com/mati865) + +## Requirements + +The easiest way to obtain these targets is cross-compilation but native build from `x86_64-pc-windows-gnu` is possible with few hacks which I don't recommend. +Std support is expected to be on pair with `*-pc-windows-gnu`. + +Binaries for this target should be at least on pair with `*-pc-windows-gnu` in terms of requirements and functionality. + +Those targets follow Windows calling convention for `extern "C"`. + +Like with any other Windows target created binaries are in PE format. + +## Building the target + +For cross-compilation I recommend using [llvm-mingw](https://github.com/mstorsjo/llvm-mingw) toolchain, one change that seems necessary beside configuring corss compilers is disabling experimental `m86k` target. Otherwise LLVM build fails with `multiple definition ...` errors. +Native bootstrapping builds require rather fragile hacks until host artifacts are avaiable so I won't describe them here. + +## Building Rust programs + +Rust does not yet ship pre-compiled artifacts for this target. To compile for +this target, you will either need to build Rust with the target enabled (see +"Building the target" above), or build your own copy of `core` by using +`build-std` or similar. + +## Testing + +Created binaries work fine on Windows or Wine using native hardware. Testing AArch64 on x86_64 is problematic though and requires spending some time with QEMU. +Once these targets bootstrap themselves on native hardware they should pass Rust testsuite. + +## Cross-compilation toolchains and C code + +Compatible C code can be built with Clang's `aarch64-pc-windows-gnu` and `x86_64-pc-windows-gnu` targets as long as LLVM based C toolchains are used. +Those include: +- [llvm-mingw](https://github.com/mstorsjo/llvm-mingw) +- [MSYS2 with CLANG* environment](https://www.msys2.org/docs/environments)