migrate compiler, bootstrap, and compiletest to windows-rs

This commit is contained in:
Andy Russell
2023-01-15 13:43:15 -05:00
parent 13b7aa4d7f
commit bb7c373fdf
22 changed files with 381 additions and 282 deletions

View File

@@ -57,7 +57,7 @@ dependencies = [
"tar",
"toml",
"walkdir",
"winapi",
"windows",
"xz2",
]
@@ -720,6 +720,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-sys"
version = "0.42.0"
@@ -736,46 +745,61 @@ dependencies = [
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.0"
name = "windows-targets"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.0"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
[[package]]
name = "windows_i686_gnu"
version = "0.42.0"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
[[package]]
name = "windows_i686_msvc"
version = "0.42.0"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.0"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.0"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.0"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
[[package]]
name = "xattr"

View File

@@ -59,18 +59,20 @@ sysinfo = { version = "0.26.0", optional = true }
[target.'cfg(not(target_os = "solaris"))'.dependencies]
fd-lock = "3.0.8"
[target.'cfg(windows)'.dependencies.winapi]
version = "0.3"
[target.'cfg(windows)'.dependencies.windows]
version = "0.46.0"
features = [
"fileapi",
"ioapiset",
"jobapi2",
"handleapi",
"winioctl",
"psapi",
"impl-default",
"timezoneapi",
"winbase",
"Win32_Foundation",
"Win32_Security",
"Win32_Storage_FileSystem",
"Win32_System_Diagnostics_Debug",
"Win32_System_IO",
"Win32_System_Ioctl",
"Win32_System_JobObjects",
"Win32_System_ProcessStatus",
"Win32_System_SystemServices",
"Win32_System_Threading",
"Win32_System_Time",
]
[dev-dependencies]

View File

@@ -281,41 +281,49 @@ fn format_rusage_data(_child: Child) -> Option<String> {
#[cfg(windows)]
fn format_rusage_data(child: Child) -> Option<String> {
use std::os::windows::io::AsRawHandle;
use winapi::um::{processthreadsapi, psapi, timezoneapi};
let handle = child.as_raw_handle();
macro_rules! try_bool {
($e:expr) => {
if $e != 1 {
return None;
}
};
}
use windows::{
Win32::Foundation::HANDLE,
Win32::System::ProcessStatus::{
K32GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS, PROCESS_MEMORY_COUNTERS_EX,
},
Win32::System::Threading::GetProcessTimes,
Win32::System::Time::FileTimeToSystemTime,
};
let handle = HANDLE(child.as_raw_handle() as isize);
let mut user_filetime = Default::default();
let mut user_time = Default::default();
let mut kernel_filetime = Default::default();
let mut kernel_time = Default::default();
let mut memory_counters = psapi::PROCESS_MEMORY_COUNTERS::default();
let mut memory_counters = PROCESS_MEMORY_COUNTERS::default();
unsafe {
try_bool!(processthreadsapi::GetProcessTimes(
GetProcessTimes(
handle,
&mut Default::default(),
&mut Default::default(),
&mut kernel_filetime,
&mut user_filetime,
));
try_bool!(timezoneapi::FileTimeToSystemTime(&user_filetime, &mut user_time));
try_bool!(timezoneapi::FileTimeToSystemTime(&kernel_filetime, &mut kernel_time));
// Unlike on Linux with RUSAGE_CHILDREN, this will only return memory information for the process
// with the given handle and none of that process's children.
try_bool!(psapi::GetProcessMemoryInfo(
handle as _,
&mut memory_counters as *mut _ as _,
std::mem::size_of::<psapi::PROCESS_MEMORY_COUNTERS_EX>() as u32,
));
)
}
.ok()
.ok()?;
unsafe { FileTimeToSystemTime(&user_filetime, &mut user_time) }.ok().ok()?;
unsafe { FileTimeToSystemTime(&kernel_filetime, &mut kernel_time) }.ok().ok()?;
// Unlike on Linux with RUSAGE_CHILDREN, this will only return memory information for the process
// with the given handle and none of that process's children.
unsafe {
K32GetProcessMemoryInfo(
handle,
&mut memory_counters,
std::mem::size_of::<PROCESS_MEMORY_COUNTERS_EX>() as u32,
)
}
.ok()
.ok()?;
// Guide on interpreting these numbers:
// https://docs.microsoft.com/en-us/windows/win32/psapi/process-memory-usage-information

View File

@@ -1303,6 +1303,14 @@ impl<'a> Builder<'a> {
}
};
// By default, windows-rs depends on a native library that doesn't get copied into the
// sysroot. Passing this cfg enables raw-dylib support instead, which makes the native
// library unnecessary. This can be removed when windows-rs enables raw-dylib
// unconditionally.
if let Mode::Rustc | Mode::ToolRustc = mode {
rustflags.arg("--cfg=windows_raw_dylib");
}
if use_new_symbol_mangling {
rustflags.arg("-Csymbol-mangling-version=v0");
} else {

View File

@@ -27,52 +27,54 @@
//! Note that this module has a #[cfg(windows)] above it as none of this logic
//! is required on Unix.
#![allow(nonstandard_style, dead_code)]
use crate::Build;
use std::env;
use std::ffi::c_void;
use std::io;
use std::mem;
use std::ptr;
use winapi::shared::minwindef::{DWORD, FALSE, LPVOID};
use winapi::um::errhandlingapi::SetErrorMode;
use winapi::um::handleapi::{CloseHandle, DuplicateHandle};
use winapi::um::jobapi2::{AssignProcessToJobObject, CreateJobObjectW, SetInformationJobObject};
use winapi::um::processthreadsapi::{GetCurrentProcess, OpenProcess};
use winapi::um::winbase::{BELOW_NORMAL_PRIORITY_CLASS, SEM_NOGPFAULTERRORBOX};
use winapi::um::winnt::{
JobObjectExtendedLimitInformation, DUPLICATE_SAME_ACCESS, JOBOBJECT_EXTENDED_LIMIT_INFORMATION,
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, JOB_OBJECT_LIMIT_PRIORITY_CLASS, PROCESS_DUP_HANDLE,
use windows::{
core::PCWSTR,
Win32::Foundation::{CloseHandle, DuplicateHandle, DUPLICATE_SAME_ACCESS, HANDLE},
Win32::System::Diagnostics::Debug::{SetErrorMode, SEM_NOGPFAULTERRORBOX, THREAD_ERROR_MODE},
Win32::System::JobObjects::{
AssignProcessToJobObject, CreateJobObjectW, JobObjectExtendedLimitInformation,
SetInformationJobObject, JOBOBJECT_EXTENDED_LIMIT_INFORMATION,
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, JOB_OBJECT_LIMIT_PRIORITY_CLASS,
},
Win32::System::Threading::{
GetCurrentProcess, OpenProcess, BELOW_NORMAL_PRIORITY_CLASS, PROCESS_DUP_HANDLE,
},
};
pub unsafe fn setup(build: &mut Build) {
// Enable the Windows Error Reporting dialog which msys disables,
// so we can JIT debug rustc
let mode = SetErrorMode(0);
let mode = SetErrorMode(THREAD_ERROR_MODE::default());
let mode = THREAD_ERROR_MODE(mode);
SetErrorMode(mode & !SEM_NOGPFAULTERRORBOX);
// Create a new job object for us to use
let job = CreateJobObjectW(ptr::null_mut(), ptr::null());
assert!(!job.is_null(), "{}", io::Error::last_os_error());
let job = CreateJobObjectW(None, PCWSTR::null()).unwrap();
// Indicate that when all handles to the job object are gone that all
// process in the object should be killed. Note that this includes our
// entire process tree by default because we've added ourselves and our
// children will reside in the job by default.
let mut info = mem::zeroed::<JOBOBJECT_EXTENDED_LIMIT_INFORMATION>();
let mut info = JOBOBJECT_EXTENDED_LIMIT_INFORMATION::default();
info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
if build.config.low_priority {
info.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PRIORITY_CLASS;
info.BasicLimitInformation.PriorityClass = BELOW_NORMAL_PRIORITY_CLASS;
info.BasicLimitInformation.PriorityClass = BELOW_NORMAL_PRIORITY_CLASS.0;
}
let r = SetInformationJobObject(
job,
JobObjectExtendedLimitInformation,
&mut info as *mut _ as LPVOID,
mem::size_of_val(&info) as DWORD,
);
assert!(r != 0, "{}", io::Error::last_os_error());
&info as *const _ as *const c_void,
mem::size_of_val(&info) as u32,
)
.ok();
assert!(r.is_ok(), "{}", io::Error::last_os_error());
// Assign our process to this job object. Note that if this fails, one very
// likely reason is that we are ourselves already in a job object! This can
@@ -83,8 +85,8 @@ pub unsafe fn setup(build: &mut Build) {
// Also note that nested jobs (why this might fail) are supported in recent
// versions of Windows, but the version of Windows that our bots are running
// at least don't support nested job objects.
let r = AssignProcessToJobObject(job, GetCurrentProcess());
if r == 0 {
let r = AssignProcessToJobObject(job, GetCurrentProcess()).ok();
if r.is_err() {
CloseHandle(job);
return;
}
@@ -102,31 +104,32 @@ pub unsafe fn setup(build: &mut Build) {
Err(..) => return,
};
let parent = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid.parse().unwrap());
let parent = match OpenProcess(PROCESS_DUP_HANDLE, false, pid.parse().unwrap()).ok() {
Some(parent) => parent,
_ => {
// If we get a null parent pointer here, it is possible that either
// we have an invalid pid or the parent process has been closed.
// Since the first case rarely happens
// (only when wrongly setting the environmental variable),
// it might be better to improve the experience of the second case
// when users have interrupted the parent process and we haven't finish
// duplicating the handle yet. We just need close the job object if that occurs.
CloseHandle(job);
return;
}
};
// If we get a null parent pointer here, it is possible that either
// we have got an invalid pid or the parent process has been closed.
// Since the first case rarely happens
// (only when wrongly setting the environmental variable),
// so it might be better to improve the experience of the second case
// when users have interrupted the parent process and we don't finish
// duplicating the handle yet.
// We just need close the job object if that occurs.
if parent.is_null() {
CloseHandle(job);
return;
}
let mut parent_handle = ptr::null_mut();
let mut parent_handle = HANDLE::default();
let r = DuplicateHandle(
GetCurrentProcess(),
job,
parent,
&mut parent_handle,
0,
FALSE,
false,
DUPLICATE_SAME_ACCESS,
);
)
.ok();
// If this failed, well at least we tried! An example of DuplicateHandle
// failing in the past has been when the wrong python2 package spawned this
@@ -134,7 +137,7 @@ pub unsafe fn setup(build: &mut Build) {
// `mingw-w64-x86_64-python2`. Not sure why it failed, but the "failure
// mode" here is that we only clean everything up when the build system
// dies, not when the python parent does, so not too bad.
if r != 0 {
if r.is_err() {
CloseHandle(job);
}
}

View File

@@ -144,6 +144,9 @@ const EXTRA_CHECK_CFGS: &[(Option<Mode>, &'static str, Option<&[&'static str]>)]
// FIXME: Used by filetime, but we should not be triggering on external dependencies.
(Some(Mode::Rustc), "emulate_second_only_system", None),
(Some(Mode::ToolRustc), "emulate_second_only_system", None),
// Needed to avoid the need to copy windows.lib into the sysroot.
(Some(Mode::Rustc), "windows_raw_dylib", None),
(Some(Mode::ToolRustc), "windows_raw_dylib", None),
];
/// A structure representing a Rust compiler.

View File

@@ -155,29 +155,30 @@ pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> {
fn symlink_dir_inner(target: &Path, junction: &Path) -> io::Result<()> {
use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt;
use std::ptr;
use winapi::shared::minwindef::{DWORD, WORD};
use winapi::um::fileapi::{CreateFileW, OPEN_EXISTING};
use winapi::um::handleapi::CloseHandle;
use winapi::um::ioapiset::DeviceIoControl;
use winapi::um::winbase::{FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OPEN_REPARSE_POINT};
use winapi::um::winioctl::FSCTL_SET_REPARSE_POINT;
use winapi::um::winnt::{
FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE, GENERIC_WRITE,
IO_REPARSE_TAG_MOUNT_POINT, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, WCHAR,
use windows::{
core::PCWSTR,
Win32::Foundation::{CloseHandle, HANDLE},
Win32::Storage::FileSystem::{
CreateFileW, FILE_ACCESS_FLAGS, FILE_FLAG_BACKUP_SEMANTICS,
FILE_FLAG_OPEN_REPARSE_POINT, FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE,
MAXIMUM_REPARSE_DATA_BUFFER_SIZE, OPEN_EXISTING,
},
Win32::System::Ioctl::FSCTL_SET_REPARSE_POINT,
Win32::System::SystemServices::{GENERIC_WRITE, IO_REPARSE_TAG_MOUNT_POINT},
Win32::System::IO::DeviceIoControl,
};
#[allow(non_snake_case)]
#[repr(C)]
struct REPARSE_MOUNTPOINT_DATA_BUFFER {
ReparseTag: DWORD,
ReparseDataLength: DWORD,
Reserved: WORD,
ReparseTargetLength: WORD,
ReparseTargetMaximumLength: WORD,
Reserved1: WORD,
ReparseTarget: WCHAR,
ReparseTag: u32,
ReparseDataLength: u32,
Reserved: u16,
ReparseTargetLength: u16,
ReparseTargetMaximumLength: u16,
Reserved1: u16,
ReparseTarget: u16,
}
fn to_u16s<S: AsRef<OsStr>>(s: S) -> io::Result<Vec<u16>> {
@@ -193,17 +194,20 @@ pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> {
let path = to_u16s(junction)?;
unsafe {
let h = CreateFileW(
path.as_ptr(),
GENERIC_WRITE,
let h = unsafe {
CreateFileW(
PCWSTR(path.as_ptr()),
FILE_ACCESS_FLAGS(GENERIC_WRITE),
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
ptr::null_mut(),
None,
OPEN_EXISTING,
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
ptr::null_mut(),
);
HANDLE::default(),
)
}
.map_err(|_| io::Error::last_os_error())?;
unsafe {
#[repr(C, align(8))]
struct Align8<T>(T);
let mut data = Align8([0u8; MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize]);
@@ -219,27 +223,29 @@ pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> {
}
*buf.offset(i) = 0;
i += 1;
(*db).ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
(*db).ReparseTargetMaximumLength = (i * 2) as WORD;
(*db).ReparseTargetLength = ((i - 1) * 2) as WORD;
(*db).ReparseDataLength = (*db).ReparseTargetLength as DWORD + 12;
(*db).ReparseTargetMaximumLength = (i * 2) as u16;
(*db).ReparseTargetLength = ((i - 1) * 2) as u16;
(*db).ReparseDataLength = ((*db).ReparseTargetLength + 12) as u32;
let mut ret = 0;
let res = DeviceIoControl(
h as *mut _,
let mut ret = 0u32;
DeviceIoControl(
h,
FSCTL_SET_REPARSE_POINT,
db.cast(),
Some(db.cast()),
(*db).ReparseDataLength + 8,
ptr::null_mut(),
None,
0,
&mut ret,
ptr::null_mut(),
);
let out = if res == 0 { Err(io::Error::last_os_error()) } else { Ok(()) };
CloseHandle(h);
out
Some(&mut ret),
None,
)
.ok()
.map_err(|_| io::Error::last_os_error())?;
}
unsafe { CloseHandle(h) };
Ok(())
}
}