Skip to content

Commit

Permalink
Add LLVM based mingw-w64 targets
Browse files Browse the repository at this point in the history
  • Loading branch information
mati865 committed May 13, 2022
1 parent a7d6408 commit 60361f2
Show file tree
Hide file tree
Showing 14 changed files with 175 additions and 18 deletions.
6 changes: 4 additions & 2 deletions compiler/rustc_codegen_llvm/src/back/archive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u16>)> = dll_imports
.iter()
Expand Down
9 changes: 5 additions & 4 deletions compiler/rustc_llvm/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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");
}
}
16 changes: 16 additions & 0 deletions compiler/rustc_target/src/spec/aarch64_pc_windows_gnullvm.rs
Original file line number Diff line number Diff line change
@@ -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,
}
}
4 changes: 4 additions & 0 deletions compiler/rustc_target/src/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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),
Expand Down
52 changes: 52 additions & 0 deletions compiler/rustc_target/src/spec/windows_gnullvm_base.rs
Original file line number Diff line number Diff line change
@@ -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<name>)
// 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()
}
}
19 changes: 19 additions & 0 deletions compiler/rustc_target/src/spec/x86_64_pc_windows_gnullvm.rs
Original file line number Diff line number Diff line change
@@ -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,
}
}
2 changes: 1 addition & 1 deletion library/unwind/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
5 changes: 5 additions & 0 deletions library/unwind/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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! {
Expand Down Expand Up @@ -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" {}
5 changes: 3 additions & 2 deletions src/bootstrap/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"))
{
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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![];
}

Expand Down
20 changes: 11 additions & 9 deletions src/bootstrap/dist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<GeneratedTarball> {
let host = self.host;
if !host.contains("pc-windows-gnu") {
if !host.ends_with("pc-windows-gnu") {
return None;
}

Expand Down Expand Up @@ -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");
}
Expand Down Expand Up @@ -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"));
}

Expand Down Expand Up @@ -1522,7 +1522,7 @@ impl Step for Extended {
prepare(tool);
}
}
if target.contains("windows-gnu") {
if target.ends_with("windows-gnu") {
prepare("rust-mingw");
}

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand All @@ -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());
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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");
Expand Down
4 changes: 4 additions & 0 deletions src/bootstrap/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
1 change: 1 addition & 0 deletions src/doc/rustc/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions src/doc/rustc/src/platform-support.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
48 changes: 48 additions & 0 deletions src/doc/rustc/src/platform-support/pc-windows-gnullvm.md
Original file line number Diff line number Diff line change
@@ -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)

0 comments on commit 60361f2

Please sign in to comment.