Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for UWP targets #60260

Merged
merged 13 commits into from
Jul 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/bootstrap/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ impl Step for StartupObjects {
fn run(self, builder: &Builder<'_>) {
let for_compiler = self.compiler;
let target = self.target;
if !target.contains("pc-windows-gnu") {
if !target.contains("windows-gnu") {
return
}

Expand Down Expand Up @@ -1126,6 +1126,7 @@ pub fn run_cargo(builder: &Builder<'_>,
// Skip files like executables
if !filename.ends_with(".rlib") &&
!filename.ends_with(".lib") &&
!filename.ends_with(".a") &&
!is_dylib(&filename) &&
!(is_check && filename.ends_with(".rmeta")) {
continue;
Expand Down
20 changes: 20 additions & 0 deletions src/librustc_codegen_ssa/back/linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,26 @@ impl<'a> Linker for GccLinker<'a> {
}
} else {
self.cmd.arg("-shared");
if self.sess.target.target.options.is_like_windows {
// The output filename already contains `dll_suffix` so
// the resulting import library will have a name in the
// form of libfoo.dll.a
let implib_name = out_filename
.file_name()
.and_then(|file| file.to_str())
.map(|file| format!("{}{}{}",
self.sess.target.target.options.staticlib_prefix,
file,
self.sess.target.target.options.staticlib_suffix));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like it's generating a file called libfoo.a, but is it intended that this is generating libfoo.dll.a?

Also does this already happen on the existing MinGW target implicitly without this argument being generated? Or otherwise?

If it's not already happening on MinGW, can this be gated to only happen for UWP?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It kind of happens implicitly with GCC/mingw as it can link directly with a DLL, while Clang can't

To be fair I'm not sure how the GNU linker handles it. My understanding is that MSVC doesn't support directly linking to a DLL and requires an import library, and clang is aiming at a feature parity with MSVC more than GCC when it comes to building for Windows.

Though that really is my sole understanding only.

In any case, it already works as is with GCC, but it also works with the implib being explicitly generated. If you prefer so, I can gate it for UWP.

Regarding the naming convention, I can definitely make it more like libfoo.dll.a, I'm not sure there's a clear and definite convention, all the import libraries from mingw are in the form libfoo.a to link with foo.dll, I think MSVC aims at foo.lib, and I've indeed seen some .dll.a

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's probably best to just go ahead and align with what MSVC is doing. I don't really understand why the MinGW UWP toolchain uses LLVM and departs from MinGW idioms, or why a MSVC-based UWP toolchain doesn't work, but we may as well try to keep things at least a little consistent on Windows as we can try...

And yes I think this block should be UWP specific because it's not needed on the MinGW toolchain.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to #29520 we emit foo.dll.lib as the import library for -msvc so to emit libfoo.dll.a for -gnu makes perfect sense for me. While MinGW is odd in that it can to some extent link to dlls without an import library, I'm in favor of always emitting import libraries on Windows regardless of the toolchain.

if let Some(implib_name) = implib_name {
let implib = out_filename
.parent()
.map(|dir| dir.join(&implib_name));
if let Some(implib) = implib {
self.linker_arg(&format!("--out-implib,{}", (*implib).to_str().unwrap()));
}
}
}
}
}

Expand Down
27 changes: 27 additions & 0 deletions src/librustc_target/spec/i686_uwp_windows_gnu.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use crate::spec::{LinkerFlavor, Target, TargetResult};

pub fn target() -> TargetResult {
let mut base = super::windows_uwp_base::opts();
base.cpu = "pentium4".to_string();
base.max_atomic_width = Some(64);
base.eliminate_frame_pointer = false; // Required for backtraces

// Mark all dynamic libraries and executables as compatible with the larger 4GiB address
// space available to x86 Windows binaries on x86_64.
base.pre_link_args
.get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,--large-address-aware".to_string());

Ok(Target {
llvm_target: "i686-pc-windows-gnu".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "32".to_string(),
target_c_int_width: "32".to_string(),
data_layout: "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32".to_string(),
arch: "x86".to_string(),
target_os: "windows".to_string(),
target_env: "gnu".to_string(),
target_vendor: "uwp".to_string(),
linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}
3 changes: 3 additions & 0 deletions src/librustc_target/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ mod solaris_base;
mod uefi_base;
mod windows_base;
mod windows_msvc_base;
mod windows_uwp_base;
mod thumb_base;
mod l4re_base;
mod fuchsia_base;
Expand Down Expand Up @@ -434,6 +435,8 @@ supported_targets! {

("x86_64-pc-windows-gnu", x86_64_pc_windows_gnu),
("i686-pc-windows-gnu", i686_pc_windows_gnu),
("i686-uwp-windows-gnu", i686_uwp_windows_gnu),
("x86_64-uwp-windows-gnu", x86_64_uwp_windows_gnu),

("aarch64-pc-windows-msvc", aarch64_pc_windows_msvc),
("x86_64-pc-windows-msvc", x86_64_pc_windows_msvc),
Expand Down
64 changes: 64 additions & 0 deletions src/librustc_target/spec/windows_uwp_base.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions};
use std::default::Default;

pub fn opts() -> TargetOptions {
let mut pre_link_args = LinkArgs::new();
pre_link_args.insert(LinkerFlavor::Gcc, vec![
// Tell GCC to avoid linker plugins, because we are not bundling
// them with Windows installer, and Rust does its own LTO anyways.
"-fno-use-linker-plugin".to_string(),

// Always enable DEP (NX bit) when it is available
"-Wl,--nxcompat".to_string(),
]);

let mut late_link_args = LinkArgs::new();
late_link_args.insert(LinkerFlavor::Gcc, vec![
//"-lwinstorecompat".to_string(),
//"-lmingwex".to_string(),
//"-lwinstorecompat".to_string(),
"-lwinstorecompat".to_string(),
"-lruntimeobject".to_string(),
"-lsynchronization".to_string(),
"-lvcruntime140_app".to_string(),
"-lucrt".to_string(),
"-lwindowsapp".to_string(),
"-lmingwex".to_string(),
"-lmingw32".to_string(),
]);

TargetOptions {
// FIXME(#13846) this should be enabled for windows
function_sections: false,
linker: Some("gcc".to_string()),
dynamic_linking: true,
executables: false,
dll_prefix: String::new(),
dll_suffix: ".dll".to_string(),
exe_suffix: ".exe".to_string(),
staticlib_prefix: "lib".to_string(),
staticlib_suffix: ".a".to_string(),
no_default_libraries: true,
target_family: Some("windows".to_string()),
is_like_windows: true,
allows_weak_linkage: false,
pre_link_args,
pre_link_objects_exe: vec![
"rsbegin.o".to_string(), // Rust compiler runtime initialization, see rsbegin.rs
],
pre_link_objects_dll: vec![
"rsbegin.o".to_string(),
],
late_link_args,
post_link_objects: vec![
"rsend.o".to_string(),
],
custom_unwind_resume: true,
abi_return_struct_as_int: true,
emit_debug_gdb_scripts: false,
requires_uwtable: true,
limit_rdylib_exports: false,

.. Default::default()
}
}
22 changes: 22 additions & 0 deletions src/librustc_target/spec/x86_64_uwp_windows_gnu.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use crate::spec::{LinkerFlavor, Target, TargetResult};

pub fn target() -> TargetResult {
let mut base = super::windows_uwp_base::opts();
base.cpu = "x86-64".to_string();
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
base.max_atomic_width = Some(64);

Ok(Target {
llvm_target: "x86_64-pc-windows-gnu".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "64".to_string(),
target_c_int_width: "32".to_string(),
data_layout: "e-m:w-i64:64-f80:128-n8:16:32:64-S128".to_string(),
arch: "x86_64".to_string(),
target_os: "windows".to_string(),
target_env: "gnu".to_string(),
target_vendor: "uwp".to_string(),
linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}
4 changes: 4 additions & 0 deletions src/libstd/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ fn main() {
println!("cargo:rustc-link-lib=framework=Security");
println!("cargo:rustc-link-lib=framework=Foundation");
println!("cargo:rustc-link-lib=resolv");
} else if target.contains("uwp") {
println!("cargo:rustc-link-lib=ws2_32");
// For BCryptGenRandom
println!("cargo:rustc-link-lib=bcrypt");
} else if target.contains("windows") {
println!("cargo:rustc-link-lib=advapi32");
println!("cargo:rustc-link-lib=ws2_32");
Expand Down
Loading