Initial vendor packages

Signed-off-by: Valentin Popov <valentin@popov.link>
This commit is contained in:
2024-01-08 01:21:28 +04:00
parent 5ecd8cf2cb
commit 1b6a04ca55
7309 changed files with 2160054 additions and 0 deletions

70
vendor/cc/src/bin/gcc-shim.rs vendored Normal file
View File

@ -0,0 +1,70 @@
#![cfg_attr(test, allow(dead_code))]
use std::env;
use std::fs::File;
use std::io::{self, prelude::*};
use std::path::PathBuf;
fn main() {
let mut args = env::args();
let program = args.next().expect("Unexpected empty args");
let out_dir = PathBuf::from(
env::var_os("GCCTEST_OUT_DIR")
.unwrap_or_else(|| panic!("{}: GCCTEST_OUT_DIR not found", program)),
);
// Find the first nonexistent candidate file to which the program's args can be written.
let candidate = (0..).find_map(|i| {
let candidate = out_dir.join(format!("out{}", i));
if candidate.exists() {
// If the file exists, commands have already run. Try again.
None
} else {
Some(candidate)
}
}).unwrap_or_else(|| panic!("Cannot find the first nonexistent candidate file to which the program's args can be written under out_dir '{}'", out_dir.display()));
// Create a file and record the args passed to the command.
let f = File::create(&candidate).unwrap_or_else(|e| {
panic!(
"{}: can't create candidate: {}, error: {}",
program,
candidate.display(),
e
)
});
let mut f = io::BufWriter::new(f);
(|| {
for arg in args {
writeln!(f, "{}", arg)?;
}
f.flush()?;
let mut f = f.into_inner()?;
f.flush()?;
f.sync_all()
})()
.unwrap_or_else(|e| {
panic!(
"{}: can't write to candidate: {}, error: {}",
program,
candidate.display(),
e
)
});
// Create a file used by some tests.
let path = &out_dir.join("libfoo.a");
File::create(path).unwrap_or_else(|e| {
panic!(
"{}: can't create libfoo.a: {}, error: {}",
program,
path.display(),
e
)
});
}

156
vendor/cc/src/com.rs vendored Normal file
View File

@ -0,0 +1,156 @@
// Copyright © 2017 winapi-rs developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
// All files in the project carrying such notice may not be copied, modified, or distributed
// except according to those terms.
#![allow(unused)]
use crate::{
winapi::{IUnknown, Interface},
windows_sys::{
CoInitializeEx, SysFreeString, SysStringLen, BSTR, COINIT_MULTITHREADED, HRESULT, S_FALSE,
S_OK,
},
};
use std::{
ffi::{OsStr, OsString},
mem::ManuallyDrop,
ops::Deref,
os::windows::ffi::{OsStrExt, OsStringExt},
ptr::{null, null_mut},
slice::from_raw_parts,
};
pub fn initialize() -> Result<(), HRESULT> {
let err = unsafe { CoInitializeEx(null(), COINIT_MULTITHREADED) };
if err != S_OK && err != S_FALSE {
// S_FALSE just means COM is already initialized
Err(err)
} else {
Ok(())
}
}
pub struct ComPtr<T>(*mut T)
where
T: Interface;
impl<T> ComPtr<T>
where
T: Interface,
{
/// Creates a `ComPtr` to wrap a raw pointer.
/// It takes ownership over the pointer which means it does __not__ call `AddRef`.
/// `T` __must__ be a COM interface that inherits from `IUnknown`.
pub unsafe fn from_raw(ptr: *mut T) -> ComPtr<T> {
assert!(!ptr.is_null());
ComPtr(ptr)
}
/// Casts up the inheritance chain
pub fn up<U>(self) -> ComPtr<U>
where
T: Deref<Target = U>,
U: Interface,
{
ComPtr(self.into_raw() as *mut U)
}
/// Extracts the raw pointer.
/// You are now responsible for releasing it yourself.
pub fn into_raw(self) -> *mut T {
ManuallyDrop::new(self).0
}
/// For internal use only.
fn as_unknown(&self) -> &IUnknown {
unsafe { &*(self.0 as *mut IUnknown) }
}
/// Performs QueryInterface fun.
pub fn cast<U>(&self) -> Result<ComPtr<U>, i32>
where
U: Interface,
{
let mut obj = null_mut();
let err = unsafe { self.as_unknown().QueryInterface(&U::uuidof(), &mut obj) };
if err < 0 {
return Err(err);
}
Ok(unsafe { ComPtr::from_raw(obj as *mut U) })
}
}
impl<T> Deref for ComPtr<T>
where
T: Interface,
{
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.0 }
}
}
impl<T> Clone for ComPtr<T>
where
T: Interface,
{
fn clone(&self) -> Self {
unsafe {
self.as_unknown().AddRef();
ComPtr::from_raw(self.0)
}
}
}
impl<T> Drop for ComPtr<T>
where
T: Interface,
{
fn drop(&mut self) {
unsafe {
self.as_unknown().Release();
}
}
}
pub struct BStr(BSTR);
impl BStr {
pub unsafe fn from_raw(s: BSTR) -> BStr {
BStr(s)
}
pub fn to_osstring(&self) -> OsString {
let len = unsafe { SysStringLen(self.0) };
let slice = unsafe { from_raw_parts(self.0, len as usize) };
OsStringExt::from_wide(slice)
}
}
impl Drop for BStr {
fn drop(&mut self) {
unsafe { SysFreeString(self.0) };
}
}
pub trait ToWide {
fn to_wide(&self) -> Vec<u16>;
fn to_wide_null(&self) -> Vec<u16>;
}
impl<T> ToWide for T
where
T: AsRef<OsStr>,
{
fn to_wide(&self) -> Vec<u16> {
self.as_ref().encode_wide().collect()
}
fn to_wide_null(&self) -> Vec<u16> {
self.as_ref().encode_wide().chain(Some(0)).collect()
}
}
pub trait FromWide
where
Self: Sized,
{
fn from_wide(wide: &[u16]) -> Self;
fn from_wide_null(wide: &[u16]) -> Self {
let len = wide.iter().take_while(|&&c| c != 0).count();
Self::from_wide(&wide[..len])
}
}
impl FromWide for OsString {
fn from_wide(wide: &[u16]) -> OsString {
OsStringExt::from_wide(wide)
}
}

4024
vendor/cc/src/lib.rs vendored Normal file

File diff suppressed because it is too large Load Diff

28
vendor/cc/src/os_pipe.rs vendored Normal file
View File

@ -0,0 +1,28 @@
//! Adapted from:
//! - https://doc.rust-lang.org/src/std/sys/unix/pipe.rs.html
//! - https://doc.rust-lang.org/src/std/sys/unix/fd.rs.html#385
//! - https://github.com/rust-lang/rust/blob/master/library/std/src/sys/mod.rs#L57
//! - https://github.com/oconnor663/os_pipe.rs
use std::fs::File;
/// Open a new pipe and return a pair of [`File`] objects for the reader and writer.
///
/// This corresponds to the `pipe2` library call on Posix and the
/// `CreatePipe` library call on Windows (though these implementation
/// details might change). These pipes are non-inheritable, so new child
/// processes won't receive a copy of them unless they're explicitly
/// passed as stdin/stdout/stderr.
pub fn pipe() -> std::io::Result<(File, File)> {
sys::pipe()
}
#[cfg(unix)]
#[path = "os_pipe/unix.rs"]
mod sys;
#[cfg(windows)]
#[path = "os_pipe/windows.rs"]
mod sys;
#[cfg(all(not(unix), not(windows)))]
compile_error!("Only unix and windows support os_pipe!");

121
vendor/cc/src/os_pipe/unix.rs vendored Normal file
View File

@ -0,0 +1,121 @@
use std::{
fs::File,
io,
os::{raw::c_int, unix::io::FromRawFd},
};
pub(super) fn pipe() -> io::Result<(File, File)> {
let mut fds = [0; 2];
// The only known way right now to create atomically set the CLOEXEC flag is
// to use the `pipe2` syscall. This was added to Linux in 2.6.27, glibc 2.9
// and musl 0.9.3, and some other targets also have it.
#[cfg(any(
target_os = "dragonfly",
target_os = "freebsd",
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd",
target_os = "redox"
))]
{
unsafe {
cvt(libc::pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC))?;
}
}
#[cfg(not(any(
target_os = "dragonfly",
target_os = "freebsd",
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd",
target_os = "redox"
)))]
{
unsafe {
cvt(libc::pipe(fds.as_mut_ptr()))?;
}
cloexec::set_cloexec(fds[0])?;
cloexec::set_cloexec(fds[1])?;
}
unsafe { Ok((File::from_raw_fd(fds[0]), File::from_raw_fd(fds[1]))) }
}
fn cvt(t: c_int) -> io::Result<c_int> {
if t == -1 {
Err(io::Error::last_os_error())
} else {
Ok(t)
}
}
#[cfg(not(any(
target_os = "dragonfly",
target_os = "freebsd",
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd",
target_os = "redox"
)))]
mod cloexec {
use super::{c_int, cvt, io};
#[cfg(not(any(
target_env = "newlib",
target_os = "solaris",
target_os = "illumos",
target_os = "emscripten",
target_os = "fuchsia",
target_os = "l4re",
target_os = "linux",
target_os = "haiku",
target_os = "redox",
target_os = "vxworks",
target_os = "nto",
)))]
pub(super) fn set_cloexec(fd: c_int) -> io::Result<()> {
unsafe {
cvt(libc::ioctl(fd, libc::FIOCLEX))?;
}
Ok(())
}
#[cfg(any(
all(
target_env = "newlib",
not(any(target_os = "espidf", target_os = "horizon"))
),
target_os = "solaris",
target_os = "illumos",
target_os = "emscripten",
target_os = "fuchsia",
target_os = "l4re",
target_os = "linux",
target_os = "haiku",
target_os = "redox",
target_os = "vxworks",
target_os = "nto",
))]
pub(super) fn set_cloexec(fd: c_int) -> io::Result<()> {
unsafe {
let previous = cvt(libc::fcntl(fd, libc::F_GETFD))?;
let new = previous | libc::FD_CLOEXEC;
if new != previous {
cvt(libc::fcntl(fd, libc::F_SETFD, new))?;
}
}
Ok(())
}
// FD_CLOEXEC is not supported in ESP-IDF and Horizon OS but there's no need to,
// because neither supports spawning processes.
#[cfg(any(target_os = "espidf", target_os = "horizon"))]
pub(super) fn set_cloexec(_fd: c_int) -> io::Result<()> {
Ok(())
}
}

24
vendor/cc/src/os_pipe/windows.rs vendored Normal file
View File

@ -0,0 +1,24 @@
use crate::windows_sys::{CreatePipe, INVALID_HANDLE_VALUE};
use std::{fs::File, io, os::windows::prelude::*, ptr};
/// NOTE: These pipes do not support IOCP.
///
/// If IOCP is needed, then you might want to emulate
/// anonymous pipes with CreateNamedPipe, as Rust's stdlib does.
pub(super) fn pipe() -> io::Result<(File, File)> {
let mut read_pipe = INVALID_HANDLE_VALUE;
let mut write_pipe = INVALID_HANDLE_VALUE;
let ret = unsafe { CreatePipe(&mut read_pipe, &mut write_pipe, ptr::null_mut(), 0) };
if ret == 0 {
Err(io::Error::last_os_error())
} else {
unsafe {
Ok((
File::from_raw_handle(read_pipe as RawHandle),
File::from_raw_handle(write_pipe as RawHandle),
))
}
}
}

190
vendor/cc/src/registry.rs vendored Normal file
View File

@ -0,0 +1,190 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::windows_sys::{
RegCloseKey, RegEnumKeyExW, RegOpenKeyExW, RegQueryValueExW, ERROR_NO_MORE_ITEMS,
ERROR_SUCCESS, HKEY, HKEY_LOCAL_MACHINE, KEY_READ, KEY_WOW64_32KEY, REG_SZ,
};
use std::{
ffi::{OsStr, OsString},
io,
ops::RangeFrom,
os::windows::prelude::*,
ptr::null_mut,
};
/// Must never be `HKEY_PERFORMANCE_DATA`.
pub(crate) struct RegistryKey(Repr);
type DWORD = u32;
struct OwnedKey(HKEY);
/// Note: must not encode `HKEY_PERFORMANCE_DATA` or one of its subkeys.
enum Repr {
/// `HKEY_LOCAL_MACHINE`.
LocalMachine,
/// A subkey of `HKEY_LOCAL_MACHINE`.
Owned(OwnedKey),
}
pub struct Iter<'a> {
idx: RangeFrom<DWORD>,
key: &'a RegistryKey,
}
unsafe impl Sync for Repr {}
unsafe impl Send for Repr {}
pub(crate) const LOCAL_MACHINE: RegistryKey = RegistryKey(Repr::LocalMachine);
impl RegistryKey {
fn raw(&self) -> HKEY {
match self.0 {
Repr::LocalMachine => HKEY_LOCAL_MACHINE,
Repr::Owned(ref val) => val.0,
}
}
/// Open a sub-key of `self`.
pub fn open(&self, key: &OsStr) -> io::Result<RegistryKey> {
let key = key.encode_wide().chain(Some(0)).collect::<Vec<_>>();
let mut ret = null_mut();
let err = unsafe {
RegOpenKeyExW(
self.raw(),
key.as_ptr(),
0,
KEY_READ | KEY_WOW64_32KEY,
&mut ret,
)
};
if err == ERROR_SUCCESS {
Ok(RegistryKey(Repr::Owned(OwnedKey(ret))))
} else {
Err(io::Error::from_raw_os_error(err as i32))
}
}
pub fn iter(&self) -> Iter {
Iter {
idx: 0..,
key: self,
}
}
pub fn query_str(&self, name: &str) -> io::Result<OsString> {
let name: &OsStr = name.as_ref();
let name = name.encode_wide().chain(Some(0)).collect::<Vec<_>>();
let mut len = 0;
let mut kind = 0;
unsafe {
let err = RegQueryValueExW(
self.raw(),
name.as_ptr(),
null_mut(),
&mut kind,
null_mut(),
&mut len,
);
if err != ERROR_SUCCESS {
return Err(io::Error::from_raw_os_error(err as i32));
}
if kind != REG_SZ {
return Err(io::Error::new(
io::ErrorKind::Other,
"registry key wasn't a string",
));
}
// The length here is the length in bytes, but we're using wide
// characters so we need to be sure to halve it for the length
// passed in.
assert!(len % 2 == 0, "impossible wide string size: {} bytes", len);
let vlen = len as usize / 2;
// Defensively initialized, see comment about
// `HKEY_PERFORMANCE_DATA` below.
let mut v = vec![0u16; vlen];
let err = RegQueryValueExW(
self.raw(),
name.as_ptr(),
null_mut(),
null_mut(),
v.as_mut_ptr() as *mut _,
&mut len,
);
// We don't check for `ERROR_MORE_DATA` (which would if the value
// grew between the first and second call to `RegQueryValueExW`),
// both because it's extremely unlikely, and this is a bit more
// defensive more defensive against weird types of registry keys.
if err != ERROR_SUCCESS {
return Err(io::Error::from_raw_os_error(err as i32));
}
// The length is allowed to change, but should still be even, as
// well as smaller.
assert!(len % 2 == 0, "impossible wide string size: {} bytes", len);
// If the length grew but returned a success code, it *probably*
// indicates we're `HKEY_PERFORMANCE_DATA` or a subkey(?). We
// consider this UB, since those keys write "undefined" or
// "unpredictable" values to len, and need to use a completely
// different loop structure. This should be impossible (and enforce
// it in the API to the best of our ability), but to mitigate the
// damage we do some smoke-checks on the len, and ensure `v` has
// been fully initialized (rather than trusting the result of
// `RegQueryValueExW`).
let actual_len = len as usize / 2;
assert!(actual_len <= v.len());
v.truncate(actual_len);
// Some registry keys may have a terminating nul character, but
// we're not interested in that, so chop it off if it's there.
if !v.is_empty() && v[v.len() - 1] == 0 {
v.pop();
}
return Ok(OsString::from_wide(&v));
}
}
}
impl Drop for OwnedKey {
fn drop(&mut self) {
unsafe {
RegCloseKey(self.0);
}
}
}
impl<'a> Iterator for Iter<'a> {
type Item = io::Result<OsString>;
fn next(&mut self) -> Option<io::Result<OsString>> {
self.idx.next().and_then(|i| unsafe {
let mut v = Vec::with_capacity(256);
let mut len = v.capacity() as DWORD;
let ret = RegEnumKeyExW(
self.key.raw(),
i,
v.as_mut_ptr(),
&mut len,
null_mut(),
null_mut(),
null_mut(),
null_mut(),
);
if ret == ERROR_NO_MORE_ITEMS {
None
} else if ret != ERROR_SUCCESS {
Some(Err(io::Error::from_raw_os_error(ret as i32)))
} else {
v.set_len(len as usize);
Some(Ok(OsString::from_wide(&v)))
}
})
}
}

283
vendor/cc/src/setup_config.rs vendored Normal file
View File

@ -0,0 +1,283 @@
// Copyright © 2017 winapi-rs developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
// All files in the project carrying such notice may not be copied, modified, or distributed
// except according to those terms.
#![allow(bad_style)]
#![allow(unused)]
use crate::{
com::{BStr, ComPtr},
winapi::{
IUnknown, IUnknownVtbl, Interface, LCID, LPCOLESTR, LPCWSTR, LPFILETIME, LPSAFEARRAY,
PULONGLONG, ULONG,
},
windows_sys::{CoCreateInstance, BSTR, CLSCTX_ALL, HRESULT, S_FALSE},
};
use std::{
ffi::OsString,
ptr::{null, null_mut},
};
// Bindings to the Setup.Configuration stuff
pub type InstanceState = u32;
pub const eNone: InstanceState = 0;
pub const eLocal: InstanceState = 1;
pub const eRegistered: InstanceState = 2;
pub const eNoRebootRequired: InstanceState = 4;
pub const eComplete: InstanceState = -1i32 as u32;
RIDL! {#[uuid(0xb41463c3, 0x8866, 0x43b5, 0xbc, 0x33, 0x2b, 0x06, 0x76, 0xf7, 0xf4, 0x2e)]
interface ISetupInstance(ISetupInstanceVtbl): IUnknown(IUnknownVtbl) {
fn GetInstanceId(
pbstrInstanceId: *mut BSTR,
) -> HRESULT,
fn GetInstallDate(
pInstallDate: LPFILETIME,
) -> HRESULT,
fn GetInstallationName(
pbstrInstallationName: *mut BSTR,
) -> HRESULT,
fn GetInstallationPath(
pbstrInstallationPath: *mut BSTR,
) -> HRESULT,
fn GetInstallationVersion(
pbstrInstallationVersion: *mut BSTR,
) -> HRESULT,
fn GetDisplayName(
lcid: LCID,
pbstrDisplayName: *mut BSTR,
) -> HRESULT,
fn GetDescription(
lcid: LCID,
pbstrDescription: *mut BSTR,
) -> HRESULT,
fn ResolvePath(
pwszRelativePath: LPCOLESTR,
pbstrAbsolutePath: *mut BSTR,
) -> HRESULT,
}}
RIDL! {#[uuid(0x89143c9a, 0x05af, 0x49b0, 0xb7, 0x17, 0x72, 0xe2, 0x18, 0xa2, 0x18, 0x5c)]
interface ISetupInstance2(ISetupInstance2Vtbl): ISetupInstance(ISetupInstanceVtbl) {
fn GetState(
pState: *mut InstanceState,
) -> HRESULT,
fn GetPackages(
ppsaPackages: *mut LPSAFEARRAY,
) -> HRESULT,
fn GetProduct(
ppPackage: *mut *mut ISetupPackageReference,
) -> HRESULT,
fn GetProductPath(
pbstrProductPath: *mut BSTR,
) -> HRESULT,
}}
RIDL! {#[uuid(0x6380bcff, 0x41d3, 0x4b2e, 0x8b, 0x2e, 0xbf, 0x8a, 0x68, 0x10, 0xc8, 0x48)]
interface IEnumSetupInstances(IEnumSetupInstancesVtbl): IUnknown(IUnknownVtbl) {
fn Next(
celt: ULONG,
rgelt: *mut *mut ISetupInstance,
pceltFetched: *mut ULONG,
) -> HRESULT,
fn Skip(
celt: ULONG,
) -> HRESULT,
fn Reset() -> HRESULT,
fn Clone(
ppenum: *mut *mut IEnumSetupInstances,
) -> HRESULT,
}}
RIDL! {#[uuid(0x42843719, 0xdb4c, 0x46c2, 0x8e, 0x7c, 0x64, 0xf1, 0x81, 0x6e, 0xfd, 0x5b)]
interface ISetupConfiguration(ISetupConfigurationVtbl): IUnknown(IUnknownVtbl) {
fn EnumInstances(
ppEnumInstances: *mut *mut IEnumSetupInstances,
) -> HRESULT,
fn GetInstanceForCurrentProcess(
ppInstance: *mut *mut ISetupInstance,
) -> HRESULT,
fn GetInstanceForPath(
wzPath: LPCWSTR,
ppInstance: *mut *mut ISetupInstance,
) -> HRESULT,
}}
RIDL! {#[uuid(0x26aab78c, 0x4a60, 0x49d6, 0xaf, 0x3b, 0x3c, 0x35, 0xbc, 0x93, 0x36, 0x5d)]
interface ISetupConfiguration2(ISetupConfiguration2Vtbl):
ISetupConfiguration(ISetupConfigurationVtbl) {
fn EnumAllInstances(
ppEnumInstances: *mut *mut IEnumSetupInstances,
) -> HRESULT,
}}
RIDL! {#[uuid(0xda8d8a16, 0xb2b6, 0x4487, 0xa2, 0xf1, 0x59, 0x4c, 0xcc, 0xcd, 0x6b, 0xf5)]
interface ISetupPackageReference(ISetupPackageReferenceVtbl): IUnknown(IUnknownVtbl) {
fn GetId(
pbstrId: *mut BSTR,
) -> HRESULT,
fn GetVersion(
pbstrVersion: *mut BSTR,
) -> HRESULT,
fn GetChip(
pbstrChip: *mut BSTR,
) -> HRESULT,
fn GetLanguage(
pbstrLanguage: *mut BSTR,
) -> HRESULT,
fn GetBranch(
pbstrBranch: *mut BSTR,
) -> HRESULT,
fn GetType(
pbstrType: *mut BSTR,
) -> HRESULT,
fn GetUniqueId(
pbstrUniqueId: *mut BSTR,
) -> HRESULT,
}}
RIDL! {#[uuid(0x42b21b78, 0x6192, 0x463e, 0x87, 0xbf, 0xd5, 0x77, 0x83, 0x8f, 0x1d, 0x5c)]
interface ISetupHelper(ISetupHelperVtbl): IUnknown(IUnknownVtbl) {
fn ParseVersion(
pwszVersion: LPCOLESTR,
pullVersion: PULONGLONG,
) -> HRESULT,
fn ParseVersionRange(
pwszVersionRange: LPCOLESTR,
pullMinVersion: PULONGLONG,
pullMaxVersion: PULONGLONG,
) -> HRESULT,
}}
DEFINE_GUID! {CLSID_SetupConfiguration,
0x177f0c4a, 0x1cd3, 0x4de7, 0xa3, 0x2c, 0x71, 0xdb, 0xbb, 0x9f, 0xa3, 0x6d}
// Safe wrapper around the COM interfaces
pub struct SetupConfiguration(ComPtr<ISetupConfiguration>);
impl SetupConfiguration {
pub fn new() -> Result<SetupConfiguration, i32> {
let mut obj = null_mut();
let err = unsafe {
CoCreateInstance(
&CLSID_SetupConfiguration,
null_mut(),
CLSCTX_ALL,
&ISetupConfiguration::uuidof(),
&mut obj,
)
};
if err < 0 {
return Err(err);
}
let obj = unsafe { ComPtr::from_raw(obj as *mut ISetupConfiguration) };
Ok(SetupConfiguration(obj))
}
pub fn get_instance_for_current_process(&self) -> Result<SetupInstance, i32> {
let mut obj = null_mut();
let err = unsafe { self.0.GetInstanceForCurrentProcess(&mut obj) };
if err < 0 {
return Err(err);
}
Ok(unsafe { SetupInstance::from_raw(obj) })
}
pub fn enum_instances(&self) -> Result<EnumSetupInstances, i32> {
let mut obj = null_mut();
let err = unsafe { self.0.EnumInstances(&mut obj) };
if err < 0 {
return Err(err);
}
Ok(unsafe { EnumSetupInstances::from_raw(obj) })
}
pub fn enum_all_instances(&self) -> Result<EnumSetupInstances, i32> {
let mut obj = null_mut();
let this = self.0.cast::<ISetupConfiguration2>()?;
let err = unsafe { this.EnumAllInstances(&mut obj) };
if err < 0 {
return Err(err);
}
Ok(unsafe { EnumSetupInstances::from_raw(obj) })
}
}
pub struct SetupInstance(ComPtr<ISetupInstance>);
impl SetupInstance {
pub unsafe fn from_raw(obj: *mut ISetupInstance) -> SetupInstance {
SetupInstance(ComPtr::from_raw(obj))
}
pub fn instance_id(&self) -> Result<OsString, i32> {
let mut s = null();
let err = unsafe { self.0.GetInstanceId(&mut s) };
let bstr = unsafe { BStr::from_raw(s) };
if err < 0 {
return Err(err);
}
Ok(bstr.to_osstring())
}
pub fn installation_name(&self) -> Result<OsString, i32> {
let mut s = null();
let err = unsafe { self.0.GetInstallationName(&mut s) };
let bstr = unsafe { BStr::from_raw(s) };
if err < 0 {
return Err(err);
}
Ok(bstr.to_osstring())
}
pub fn installation_path(&self) -> Result<OsString, i32> {
let mut s = null();
let err = unsafe { self.0.GetInstallationPath(&mut s) };
let bstr = unsafe { BStr::from_raw(s) };
if err < 0 {
return Err(err);
}
Ok(bstr.to_osstring())
}
pub fn installation_version(&self) -> Result<OsString, i32> {
let mut s = null();
let err = unsafe { self.0.GetInstallationVersion(&mut s) };
let bstr = unsafe { BStr::from_raw(s) };
if err < 0 {
return Err(err);
}
Ok(bstr.to_osstring())
}
pub fn product_path(&self) -> Result<OsString, i32> {
let mut s = null();
let this = self.0.cast::<ISetupInstance2>()?;
let err = unsafe { this.GetProductPath(&mut s) };
let bstr = unsafe { BStr::from_raw(s) };
if err < 0 {
return Err(err);
}
Ok(bstr.to_osstring())
}
}
pub struct EnumSetupInstances(ComPtr<IEnumSetupInstances>);
impl EnumSetupInstances {
pub unsafe fn from_raw(obj: *mut IEnumSetupInstances) -> EnumSetupInstances {
EnumSetupInstances(ComPtr::from_raw(obj))
}
}
impl Iterator for EnumSetupInstances {
type Item = Result<SetupInstance, i32>;
fn next(&mut self) -> Option<Result<SetupInstance, i32>> {
let mut obj = null_mut();
let err = unsafe { self.0.Next(1, &mut obj, null_mut()) };
if err < 0 {
return Some(Err(err));
}
if err == S_FALSE {
return None;
}
Some(Ok(unsafe { SetupInstance::from_raw(obj) }))
}
}

199
vendor/cc/src/vs_instances.rs vendored Normal file
View File

@ -0,0 +1,199 @@
use std::borrow::Cow;
use std::collections::HashMap;
use std::convert::TryFrom;
use std::io::BufRead;
use std::path::PathBuf;
use crate::setup_config::{EnumSetupInstances, SetupInstance};
pub enum VsInstance {
Com(SetupInstance),
Vswhere(VswhereInstance),
}
impl VsInstance {
pub fn installation_name(&self) -> Option<Cow<str>> {
match self {
VsInstance::Com(s) => s
.installation_name()
.ok()
.and_then(|s| s.into_string().ok())
.map(Cow::from),
VsInstance::Vswhere(v) => v.map.get("installationName").map(Cow::from),
}
}
pub fn installation_path(&self) -> Option<PathBuf> {
match self {
VsInstance::Com(s) => s.installation_path().ok().map(PathBuf::from),
VsInstance::Vswhere(v) => v.map.get("installationPath").map(PathBuf::from),
}
}
pub fn installation_version(&self) -> Option<Cow<str>> {
match self {
VsInstance::Com(s) => s
.installation_version()
.ok()
.and_then(|s| s.into_string().ok())
.map(Cow::from),
VsInstance::Vswhere(v) => v.map.get("installationVersion").map(Cow::from),
}
}
}
pub enum VsInstances {
ComBased(EnumSetupInstances),
VswhereBased(VswhereInstance),
}
impl IntoIterator for VsInstances {
type Item = VsInstance;
#[allow(bare_trait_objects)]
type IntoIter = Box<Iterator<Item = Self::Item>>;
fn into_iter(self) -> Self::IntoIter {
match self {
VsInstances::ComBased(e) => {
Box::new(e.into_iter().filter_map(Result::ok).map(VsInstance::Com))
}
VsInstances::VswhereBased(v) => Box::new(std::iter::once(VsInstance::Vswhere(v))),
}
}
}
#[derive(Debug)]
pub struct VswhereInstance {
map: HashMap<String, String>,
}
impl TryFrom<&Vec<u8>> for VswhereInstance {
type Error = &'static str;
fn try_from(output: &Vec<u8>) -> Result<Self, Self::Error> {
let map: HashMap<_, _> = output
.lines()
.filter_map(Result::ok)
.filter_map(|s| {
let mut splitn = s.splitn(2, ": ");
Some((splitn.next()?.to_owned(), splitn.next()?.to_owned()))
})
.collect();
if !map.contains_key("installationName")
|| !map.contains_key("installationPath")
|| !map.contains_key("installationVersion")
{
return Err("required properties not found");
}
Ok(Self { map })
}
}
#[cfg(test)]
mod tests_ {
use std::borrow::Cow;
use std::convert::TryFrom;
use std::path::PathBuf;
#[test]
fn it_parses_vswhere_output_correctly() {
let output = br"instanceId: 58104422
installDate: 21/02/2021 21:50:33
installationName: VisualStudio/16.9.2+31112.23
installationPath: C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools
installationVersion: 16.9.31112.23
productId: Microsoft.VisualStudio.Product.BuildTools
productPath: C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\Common7\Tools\LaunchDevCmd.bat
state: 4294967295
isComplete: 1
isLaunchable: 1
isPrerelease: 0
isRebootRequired: 0
displayName: Visual Studio Build Tools 2019
description: The Visual Studio Build Tools allows you to build native and managed MSBuild-based applications without requiring the Visual Studio IDE. There are options to install the Visual C++ compilers and libraries, MFC, ATL, and C++/CLI support.
channelId: VisualStudio.16.Release
channelUri: https://aka.ms/vs/16/release/channel
enginePath: C:\Program Files (x86)\Microsoft Visual Studio\Installer\resources\app\ServiceHub\Services\Microsoft.VisualStudio.Setup.Service
releaseNotes: https://docs.microsoft.com/en-us/visualstudio/releases/2019/release-notes-v16.9#16.9.2
thirdPartyNotices: https://go.microsoft.com/fwlink/?LinkId=660909
updateDate: 2021-03-17T21:16:46.5963702Z
catalog_buildBranch: d16.9
catalog_buildVersion: 16.9.31112.23
catalog_id: VisualStudio/16.9.2+31112.23
catalog_localBuild: build-lab
catalog_manifestName: VisualStudio
catalog_manifestType: installer
catalog_productDisplayVersion: 16.9.2
catalog_productLine: Dev16
catalog_productLineVersion: 2019
catalog_productMilestone: RTW
catalog_productMilestoneIsPreRelease: False
catalog_productName: Visual Studio
catalog_productPatchVersion: 2
catalog_productPreReleaseMilestoneSuffix: 1.0
catalog_productSemanticVersion: 16.9.2+31112.23
catalog_requiredEngineVersion: 2.9.3365.38425
properties_campaignId: 156063665.1613940062
properties_channelManifestId: VisualStudio.16.Release/16.9.2+31112.23
properties_nickname:
properties_setupEngineFilePath: C:\Program Files (x86)\Microsoft Visual Studio\Installer\vs_installershell.exe
"
.to_vec();
let vswhere_instance = super::VswhereInstance::try_from(&output);
assert!(vswhere_instance.is_ok());
let vs_instance = super::VsInstance::Vswhere(vswhere_instance.unwrap());
assert_eq!(
vs_instance.installation_name(),
Some(Cow::from("VisualStudio/16.9.2+31112.23"))
);
assert_eq!(
vs_instance.installation_path(),
Some(PathBuf::from(
r"C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools"
))
);
assert_eq!(
vs_instance.installation_version(),
Some(Cow::from("16.9.31112.23"))
);
}
#[test]
fn it_returns_an_error_for_empty_output() {
let output = b"".to_vec();
let vswhere_instance = super::VswhereInstance::try_from(&output);
assert!(vswhere_instance.is_err());
}
#[test]
fn it_returns_an_error_for_output_consisting_of_empty_lines() {
let output = br"
"
.to_vec();
let vswhere_instance = super::VswhereInstance::try_from(&output);
assert!(vswhere_instance.is_err());
}
#[test]
fn it_returns_an_error_for_output_without_required_properties() {
let output = br"instanceId: 58104422
installDate: 21/02/2021 21:50:33
productId: Microsoft.VisualStudio.Product.BuildTools
productPath: C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\Common7\Tools\LaunchDevCmd.bat
"
.to_vec();
let vswhere_instance = super::VswhereInstance::try_from(&output);
assert!(vswhere_instance.is_err());
}
}

146
vendor/cc/src/winapi.rs vendored Normal file
View File

@ -0,0 +1,146 @@
// Copyright © 2015-2017 winapi-rs developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
// All files in the project carrying such notice may not be copied, modified, or distributed
// except according to those terms.
#![allow(bad_style)]
use std::os::raw;
pub type wchar_t = u16;
pub use crate::windows_sys::{FILETIME, GUID, HRESULT, SAFEARRAY, SAFEARRAYBOUND};
pub type REFIID = *const IID;
pub type IID = GUID;
pub type ULONG = raw::c_ulong;
pub type DWORD = u32;
pub type LPFILETIME = *mut FILETIME;
pub type OLECHAR = WCHAR;
pub type WCHAR = wchar_t;
pub type LPCOLESTR = *const OLECHAR;
pub type LCID = DWORD;
pub type LPCWSTR = *const WCHAR;
pub type PULONGLONG = *mut ULONGLONG;
pub type ULONGLONG = u64;
pub trait Interface {
fn uuidof() -> GUID;
}
pub type LPSAFEARRAY = *mut SAFEARRAY;
macro_rules! DEFINE_GUID {
(
$name:ident, $l:expr, $w1:expr, $w2:expr,
$b1:expr, $b2:expr, $b3:expr, $b4:expr, $b5:expr, $b6:expr, $b7:expr, $b8:expr
) => {
pub const $name: $crate::winapi::GUID = $crate::winapi::GUID {
data1: $l,
data2: $w1,
data3: $w2,
data4: [$b1, $b2, $b3, $b4, $b5, $b6, $b7, $b8],
};
};
}
macro_rules! RIDL {
(#[uuid($($uuid:expr),+)]
interface $interface:ident ($vtbl:ident) {$(
fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty,
)+}) => (
#[repr(C)]
pub struct $vtbl {
$(pub $method: unsafe extern "system" fn(
This: *mut $interface,
$($p: $t),*
) -> $rtr,)+
}
#[repr(C)]
pub struct $interface {
pub lpVtbl: *const $vtbl,
}
RIDL!{@impl $interface {$(fn $method($($p: $t,)*) -> $rtr,)+}}
RIDL!{@uuid $interface $($uuid),+}
);
(#[uuid($($uuid:expr),+)]
interface $interface:ident ($vtbl:ident) : $pinterface:ident ($pvtbl:ident) {
}) => (
#[repr(C)]
pub struct $vtbl {
pub parent: $pvtbl,
}
#[repr(C)]
pub struct $interface {
pub lpVtbl: *const $vtbl,
}
RIDL!{@deref $interface $pinterface}
RIDL!{@uuid $interface $($uuid),+}
);
(#[uuid($($uuid:expr),+)]
interface $interface:ident ($vtbl:ident) : $pinterface:ident ($pvtbl:ident) {$(
fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty,
)+}) => (
#[repr(C)]
pub struct $vtbl {
pub parent: $pvtbl,
$(pub $method: unsafe extern "system" fn(
This: *mut $interface,
$($p: $t,)*
) -> $rtr,)+
}
#[repr(C)]
pub struct $interface {
pub lpVtbl: *const $vtbl,
}
RIDL!{@impl $interface {$(fn $method($($p: $t,)*) -> $rtr,)+}}
RIDL!{@deref $interface $pinterface}
RIDL!{@uuid $interface $($uuid),+}
);
(@deref $interface:ident $pinterface:ident) => (
impl ::std::ops::Deref for $interface {
type Target = $pinterface;
#[inline]
fn deref(&self) -> &$pinterface {
unsafe { &*(self as *const $interface as *const $pinterface) }
}
}
);
(@impl $interface:ident {$(
fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty,
)+}) => (
impl $interface {
$(#[inline] pub unsafe fn $method(&self, $($p: $t,)*) -> $rtr {
((*self.lpVtbl).$method)(self as *const _ as *mut _, $($p,)*)
})+
}
);
(@uuid $interface:ident
$l:expr, $w1:expr, $w2:expr,
$b1:expr, $b2:expr, $b3:expr, $b4:expr, $b5:expr, $b6:expr, $b7:expr, $b8:expr
) => (
impl $crate::winapi::Interface for $interface {
#[inline]
fn uuidof() -> $crate::winapi::GUID {
$crate::winapi::GUID {
data1: $l,
data2: $w1,
data3: $w2,
data4: [$b1, $b2, $b3, $b4, $b5, $b6, $b7, $b8],
}
}
}
);
}
RIDL! {#[uuid(0x00000000, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)]
interface IUnknown(IUnknownVtbl) {
fn QueryInterface(
riid: REFIID,
ppvObject: *mut *mut raw::c_void,
) -> HRESULT,
fn AddRef() -> ULONG,
fn Release() -> ULONG,
}}

896
vendor/cc/src/windows_registry.rs vendored Normal file
View File

@ -0,0 +1,896 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! A helper module to probe the Windows Registry when looking for
//! windows-specific tools.
use std::process::Command;
use crate::Tool;
#[cfg(windows)]
use crate::ToolFamily;
#[cfg(windows)]
const MSVC_FAMILY: ToolFamily = ToolFamily::Msvc { clang_cl: false };
/// Attempts to find a tool within an MSVC installation using the Windows
/// registry as a point to search from.
///
/// The `target` argument is the target that the tool should work for (e.g.
/// compile or link for) and the `tool` argument is the tool to find (e.g.
/// `cl.exe` or `link.exe`).
///
/// This function will return `None` if the tool could not be found, or it will
/// return `Some(cmd)` which represents a command that's ready to execute the
/// tool with the appropriate environment variables set.
///
/// Note that this function always returns `None` for non-MSVC targets.
pub fn find(target: &str, tool: &str) -> Option<Command> {
find_tool(target, tool).map(|c| c.to_command())
}
/// Similar to the `find` function above, this function will attempt the same
/// operation (finding a MSVC tool in a local install) but instead returns a
/// `Tool` which may be introspected.
#[cfg(not(windows))]
pub fn find_tool(_target: &str, _tool: &str) -> Option<Tool> {
None
}
/// Documented above.
#[cfg(windows)]
pub fn find_tool(target: &str, tool: &str) -> Option<Tool> {
// This logic is all tailored for MSVC, if we're not that then bail out
// early.
if !target.contains("msvc") {
return None;
}
// Looks like msbuild isn't located in the same location as other tools like
// cl.exe and lib.exe. To handle this we probe for it manually with
// dedicated registry keys.
if tool.contains("msbuild") {
return impl_::find_msbuild(target);
}
if tool.contains("devenv") {
return impl_::find_devenv(target);
}
// Ok, if we're here, now comes the fun part of the probing. Default shells
// or shells like MSYS aren't really configured to execute `cl.exe` and the
// various compiler tools shipped as part of Visual Studio. Here we try to
// first find the relevant tool, then we also have to be sure to fill in
// environment variables like `LIB`, `INCLUDE`, and `PATH` to ensure that
// the tool is actually usable.
return impl_::find_msvc_environment(tool, target)
.or_else(|| impl_::find_msvc_15plus(tool, target))
.or_else(|| impl_::find_msvc_14(tool, target))
.or_else(|| impl_::find_msvc_12(tool, target))
.or_else(|| impl_::find_msvc_11(tool, target));
}
/// A version of Visual Studio
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[non_exhaustive]
pub enum VsVers {
/// Visual Studio 12 (2013)
Vs12,
/// Visual Studio 14 (2015)
Vs14,
/// Visual Studio 15 (2017)
Vs15,
/// Visual Studio 16 (2019)
Vs16,
/// Visual Studio 17 (2022)
Vs17,
}
/// Find the most recent installed version of Visual Studio
///
/// This is used by the cmake crate to figure out the correct
/// generator.
#[cfg(not(windows))]
pub fn find_vs_version() -> Result<VsVers, String> {
Err("not windows".to_string())
}
/// Documented above
#[cfg(windows)]
pub fn find_vs_version() -> Result<VsVers, String> {
use std::env;
match env::var("VisualStudioVersion") {
Ok(version) => match &version[..] {
"17.0" => Ok(VsVers::Vs17),
"16.0" => Ok(VsVers::Vs16),
"15.0" => Ok(VsVers::Vs15),
"14.0" => Ok(VsVers::Vs14),
"12.0" => Ok(VsVers::Vs12),
vers => Err(format!(
"\n\n\
unsupported or unknown VisualStudio version: {}\n\
if another version is installed consider running \
the appropriate vcvars script before building this \
crate\n\
",
vers
)),
},
_ => {
// Check for the presence of a specific registry key
// that indicates visual studio is installed.
if impl_::has_msbuild_version("17.0") {
Ok(VsVers::Vs17)
} else if impl_::has_msbuild_version("16.0") {
Ok(VsVers::Vs16)
} else if impl_::has_msbuild_version("15.0") {
Ok(VsVers::Vs15)
} else if impl_::has_msbuild_version("14.0") {
Ok(VsVers::Vs14)
} else if impl_::has_msbuild_version("12.0") {
Ok(VsVers::Vs12)
} else {
Err(format!(
"\n\n\
couldn't determine visual studio generator\n\
if VisualStudio is installed, however, consider \
running the appropriate vcvars script before building \
this crate\n\
"
))
}
}
}
}
#[cfg(windows)]
mod impl_ {
use crate::com;
use crate::registry::{RegistryKey, LOCAL_MACHINE};
use crate::setup_config::SetupConfiguration;
use crate::vs_instances::{VsInstances, VswhereInstance};
use std::convert::TryFrom;
use std::env;
use std::ffi::OsString;
use std::fs::File;
use std::io::Read;
use std::iter;
use std::mem;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::str::FromStr;
use super::MSVC_FAMILY;
use crate::Tool;
struct MsvcTool {
tool: PathBuf,
libs: Vec<PathBuf>,
path: Vec<PathBuf>,
include: Vec<PathBuf>,
}
impl MsvcTool {
fn new(tool: PathBuf) -> MsvcTool {
MsvcTool {
tool: tool,
libs: Vec::new(),
path: Vec::new(),
include: Vec::new(),
}
}
fn into_tool(self) -> Tool {
let MsvcTool {
tool,
libs,
path,
include,
} = self;
let mut tool = Tool::with_family(tool.into(), MSVC_FAMILY);
add_env(&mut tool, "LIB", libs);
add_env(&mut tool, "PATH", path);
add_env(&mut tool, "INCLUDE", include);
tool
}
}
/// Checks to see if the `VSCMD_ARG_TGT_ARCH` environment variable matches the
/// given target's arch. Returns `None` if the variable does not exist.
#[cfg(windows)]
fn is_vscmd_target(target: &str) -> Option<bool> {
let vscmd_arch = env::var("VSCMD_ARG_TGT_ARCH").ok()?;
// Convert the Rust target arch to its VS arch equivalent.
let arch = match target.split("-").next() {
Some("x86_64") => "x64",
Some("aarch64") => "arm64",
Some("i686") | Some("i586") => "x86",
Some("thumbv7a") => "arm",
// An unrecognized arch.
_ => return Some(false),
};
Some(vscmd_arch == arch)
}
/// Attempt to find the tool using environment variables set by vcvars.
pub fn find_msvc_environment(tool: &str, target: &str) -> Option<Tool> {
// Early return if the environment doesn't contain a VC install.
if env::var_os("VCINSTALLDIR").is_none() {
return None;
}
let vs_install_dir = env::var_os("VSINSTALLDIR")?.into();
// If the vscmd target differs from the requested target then
// attempt to get the tool using the VS install directory.
if is_vscmd_target(target) == Some(false) {
// We will only get here with versions 15+.
tool_from_vs15plus_instance(tool, target, &vs_install_dir)
} else {
// Fallback to simply using the current environment.
env::var_os("PATH")
.and_then(|path| {
env::split_paths(&path)
.map(|p| p.join(tool))
.find(|p| p.exists())
})
.map(|path| Tool::with_family(path.into(), MSVC_FAMILY))
}
}
fn find_msbuild_vs17(target: &str) -> Option<Tool> {
find_tool_in_vs16plus_path(r"MSBuild\Current\Bin\MSBuild.exe", target, "17")
}
#[allow(bare_trait_objects)]
fn vs16plus_instances(target: &str, version: &'static str) -> Box<Iterator<Item = PathBuf>> {
let instances = if let Some(instances) = vs15plus_instances(target) {
instances
} else {
return Box::new(iter::empty());
};
Box::new(instances.into_iter().filter_map(move |instance| {
let installation_name = instance.installation_name()?;
if installation_name.starts_with(&format!("VisualStudio/{}.", version)) {
Some(instance.installation_path()?)
} else if installation_name.starts_with(&format!("VisualStudioPreview/{}.", version)) {
Some(instance.installation_path()?)
} else {
None
}
}))
}
fn find_tool_in_vs16plus_path(tool: &str, target: &str, version: &'static str) -> Option<Tool> {
vs16plus_instances(target, version)
.filter_map(|path| {
let path = path.join(tool);
if !path.is_file() {
return None;
}
let mut tool = Tool::with_family(path, MSVC_FAMILY);
if target.contains("x86_64") {
tool.env.push(("Platform".into(), "X64".into()));
}
if target.contains("aarch64") {
tool.env.push(("Platform".into(), "ARM64".into()));
}
Some(tool)
})
.next()
}
fn find_msbuild_vs16(target: &str) -> Option<Tool> {
find_tool_in_vs16plus_path(r"MSBuild\Current\Bin\MSBuild.exe", target, "16")
}
// In MSVC 15 (2017) MS once again changed the scheme for locating
// the tooling. Now we must go through some COM interfaces, which
// is super fun for Rust.
//
// Note that much of this logic can be found [online] wrt paths, COM, etc.
//
// [online]: https://blogs.msdn.microsoft.com/vcblog/2017/03/06/finding-the-visual-c-compiler-tools-in-visual-studio-2017/
//
// Returns MSVC 15+ instances (15, 16 right now), the order should be consider undefined.
//
// However, on ARM64 this method doesn't work because VS Installer fails to register COM component on ARM64.
// Hence, as the last resort we try to use vswhere.exe to list available instances.
fn vs15plus_instances(target: &str) -> Option<VsInstances> {
vs15plus_instances_using_com().or_else(|| vs15plus_instances_using_vswhere(target))
}
fn vs15plus_instances_using_com() -> Option<VsInstances> {
com::initialize().ok()?;
let config = SetupConfiguration::new().ok()?;
let enum_setup_instances = config.enum_all_instances().ok()?;
Some(VsInstances::ComBased(enum_setup_instances))
}
fn vs15plus_instances_using_vswhere(target: &str) -> Option<VsInstances> {
let program_files_path: PathBuf = env::var("ProgramFiles(x86)")
.or_else(|_| env::var("ProgramFiles"))
.ok()?
.into();
let vswhere_path =
program_files_path.join(r"Microsoft Visual Studio\Installer\vswhere.exe");
if !vswhere_path.exists() {
return None;
}
let arch = target.split('-').next().unwrap();
let tools_arch = match arch {
"i586" | "i686" | "x86_64" => Some("x86.x64"),
"arm" | "thumbv7a" => Some("ARM"),
"aarch64" => Some("ARM64"),
_ => None,
};
let vswhere_output = Command::new(vswhere_path)
.args(&[
"-latest",
"-products",
"*",
"-requires",
&format!("Microsoft.VisualStudio.Component.VC.Tools.{}", tools_arch?),
"-format",
"text",
"-nologo",
])
.stderr(std::process::Stdio::inherit())
.output()
.ok()?;
let vs_instances =
VsInstances::VswhereBased(VswhereInstance::try_from(&vswhere_output.stdout).ok()?);
Some(vs_instances)
}
// Inspired from official microsoft/vswhere ParseVersionString
// i.e. at most four u16 numbers separated by '.'
fn parse_version(version: &str) -> Option<Vec<u16>> {
version
.split('.')
.map(|chunk| u16::from_str(chunk).ok())
.collect()
}
pub fn find_msvc_15plus(tool: &str, target: &str) -> Option<Tool> {
let iter = vs15plus_instances(target)?;
iter.into_iter()
.filter_map(|instance| {
let version = parse_version(&instance.installation_version()?)?;
let instance_path = instance.installation_path()?;
let tool = tool_from_vs15plus_instance(tool, target, &instance_path)?;
Some((version, tool))
})
.max_by(|(a_version, _), (b_version, _)| a_version.cmp(b_version))
.map(|(_version, tool)| tool)
}
// While the paths to Visual Studio 2017's devenv and MSBuild could
// potentially be retrieved from the registry, finding them via
// SetupConfiguration has shown to be [more reliable], and is preferred
// according to Microsoft. To help head off potential regressions though,
// we keep the registry method as a fallback option.
//
// [more reliable]: https://github.com/rust-lang/cc-rs/pull/331
fn find_tool_in_vs15_path(tool: &str, target: &str) -> Option<Tool> {
let mut path = match vs15plus_instances(target) {
Some(instances) => instances
.into_iter()
.filter_map(|instance| instance.installation_path())
.map(|path| path.join(tool))
.find(|ref path| path.is_file()),
None => None,
};
if path.is_none() {
let key = r"SOFTWARE\WOW6432Node\Microsoft\VisualStudio\SxS\VS7";
path = LOCAL_MACHINE
.open(key.as_ref())
.ok()
.and_then(|key| key.query_str("15.0").ok())
.map(|path| PathBuf::from(path).join(tool))
.and_then(|path| if path.is_file() { Some(path) } else { None });
}
path.map(|path| {
let mut tool = Tool::with_family(path, MSVC_FAMILY);
if target.contains("x86_64") {
tool.env.push(("Platform".into(), "X64".into()));
}
if target.contains("aarch64") {
tool.env.push(("Platform".into(), "ARM64".into()));
}
tool
})
}
fn tool_from_vs15plus_instance(
tool: &str,
target: &str,
instance_path: &PathBuf,
) -> Option<Tool> {
let (root_path, bin_path, host_dylib_path, lib_path, include_path) =
vs15plus_vc_paths(target, instance_path)?;
let tool_path = bin_path.join(tool);
if !tool_path.exists() {
return None;
};
let mut tool = MsvcTool::new(tool_path);
tool.path.push(bin_path.clone());
tool.path.push(host_dylib_path);
tool.libs.push(lib_path);
tool.include.push(include_path);
if let Some((atl_lib_path, atl_include_path)) = atl_paths(target, &root_path) {
tool.libs.push(atl_lib_path);
tool.include.push(atl_include_path);
}
add_sdks(&mut tool, target)?;
Some(tool.into_tool())
}
fn vs15plus_vc_paths(
target: &str,
instance_path: &PathBuf,
) -> Option<(PathBuf, PathBuf, PathBuf, PathBuf, PathBuf)> {
let version_path =
instance_path.join(r"VC\Auxiliary\Build\Microsoft.VCToolsVersion.default.txt");
let mut version_file = File::open(version_path).ok()?;
let mut version = String::new();
version_file.read_to_string(&mut version).ok()?;
let version = version.trim();
let host = match host_arch() {
X86 => "X86",
X86_64 => "X64",
// There is no natively hosted compiler on ARM64.
// Instead, use the x86 toolchain under emulation (there is no x64 emulation).
AARCH64 => "X86",
_ => return None,
};
let target = lib_subdir(target)?;
// The directory layout here is MSVC/bin/Host$host/$target/
let path = instance_path.join(r"VC\Tools\MSVC").join(version);
// This is the path to the toolchain for a particular target, running
// on a given host
let bin_path = path
.join("bin")
.join(&format!("Host{}", host))
.join(&target);
// But! we also need PATH to contain the target directory for the host
// architecture, because it contains dlls like mspdb140.dll compiled for
// the host architecture.
let host_dylib_path = path
.join("bin")
.join(&format!("Host{}", host))
.join(&host.to_lowercase());
let lib_path = path.join("lib").join(&target);
let include_path = path.join("include");
Some((path, bin_path, host_dylib_path, lib_path, include_path))
}
fn atl_paths(target: &str, path: &Path) -> Option<(PathBuf, PathBuf)> {
let atl_path = path.join("atlmfc");
let sub = lib_subdir(target)?;
if atl_path.exists() {
Some((atl_path.join("lib").join(sub), atl_path.join("include")))
} else {
None
}
}
// For MSVC 14 we need to find the Universal CRT as well as either
// the Windows 10 SDK or Windows 8.1 SDK.
pub fn find_msvc_14(tool: &str, target: &str) -> Option<Tool> {
let vcdir = get_vc_dir("14.0")?;
let mut tool = get_tool(tool, &vcdir, target)?;
add_sdks(&mut tool, target)?;
Some(tool.into_tool())
}
fn add_sdks(tool: &mut MsvcTool, target: &str) -> Option<()> {
let sub = lib_subdir(target)?;
let (ucrt, ucrt_version) = get_ucrt_dir()?;
let host = match host_arch() {
X86 => "x86",
X86_64 => "x64",
AARCH64 => "arm64",
_ => return None,
};
tool.path
.push(ucrt.join("bin").join(&ucrt_version).join(host));
let ucrt_include = ucrt.join("include").join(&ucrt_version);
tool.include.push(ucrt_include.join("ucrt"));
let ucrt_lib = ucrt.join("lib").join(&ucrt_version);
tool.libs.push(ucrt_lib.join("ucrt").join(sub));
if let Some((sdk, version)) = get_sdk10_dir() {
tool.path.push(sdk.join("bin").join(host));
let sdk_lib = sdk.join("lib").join(&version);
tool.libs.push(sdk_lib.join("um").join(sub));
let sdk_include = sdk.join("include").join(&version);
tool.include.push(sdk_include.join("um"));
tool.include.push(sdk_include.join("cppwinrt"));
tool.include.push(sdk_include.join("winrt"));
tool.include.push(sdk_include.join("shared"));
} else if let Some(sdk) = get_sdk81_dir() {
tool.path.push(sdk.join("bin").join(host));
let sdk_lib = sdk.join("lib").join("winv6.3");
tool.libs.push(sdk_lib.join("um").join(sub));
let sdk_include = sdk.join("include");
tool.include.push(sdk_include.join("um"));
tool.include.push(sdk_include.join("winrt"));
tool.include.push(sdk_include.join("shared"));
}
Some(())
}
// For MSVC 12 we need to find the Windows 8.1 SDK.
pub fn find_msvc_12(tool: &str, target: &str) -> Option<Tool> {
let vcdir = get_vc_dir("12.0")?;
let mut tool = get_tool(tool, &vcdir, target)?;
let sub = lib_subdir(target)?;
let sdk81 = get_sdk81_dir()?;
tool.path.push(sdk81.join("bin").join(sub));
let sdk_lib = sdk81.join("lib").join("winv6.3");
tool.libs.push(sdk_lib.join("um").join(sub));
let sdk_include = sdk81.join("include");
tool.include.push(sdk_include.join("shared"));
tool.include.push(sdk_include.join("um"));
tool.include.push(sdk_include.join("winrt"));
Some(tool.into_tool())
}
// For MSVC 11 we need to find the Windows 8 SDK.
pub fn find_msvc_11(tool: &str, target: &str) -> Option<Tool> {
let vcdir = get_vc_dir("11.0")?;
let mut tool = get_tool(tool, &vcdir, target)?;
let sub = lib_subdir(target)?;
let sdk8 = get_sdk8_dir()?;
tool.path.push(sdk8.join("bin").join(sub));
let sdk_lib = sdk8.join("lib").join("win8");
tool.libs.push(sdk_lib.join("um").join(sub));
let sdk_include = sdk8.join("include");
tool.include.push(sdk_include.join("shared"));
tool.include.push(sdk_include.join("um"));
tool.include.push(sdk_include.join("winrt"));
Some(tool.into_tool())
}
fn add_env(tool: &mut Tool, env: &str, paths: Vec<PathBuf>) {
let prev = env::var_os(env).unwrap_or(OsString::new());
let prev = env::split_paths(&prev);
let new = paths.into_iter().chain(prev);
tool.env
.push((env.to_string().into(), env::join_paths(new).unwrap()));
}
// Given a possible MSVC installation directory, we look for the linker and
// then add the MSVC library path.
fn get_tool(tool: &str, path: &Path, target: &str) -> Option<MsvcTool> {
bin_subdir(target)
.into_iter()
.map(|(sub, host)| {
(
path.join("bin").join(sub).join(tool),
path.join("bin").join(host),
)
})
.filter(|&(ref path, _)| path.is_file())
.map(|(path, host)| {
let mut tool = MsvcTool::new(path);
tool.path.push(host);
tool
})
.filter_map(|mut tool| {
let sub = vc_lib_subdir(target)?;
tool.libs.push(path.join("lib").join(sub));
tool.include.push(path.join("include"));
let atlmfc_path = path.join("atlmfc");
if atlmfc_path.exists() {
tool.libs.push(atlmfc_path.join("lib").join(sub));
tool.include.push(atlmfc_path.join("include"));
}
Some(tool)
})
.next()
}
// To find MSVC we look in a specific registry key for the version we are
// trying to find.
fn get_vc_dir(ver: &str) -> Option<PathBuf> {
let key = r"SOFTWARE\Microsoft\VisualStudio\SxS\VC7";
let key = LOCAL_MACHINE.open(key.as_ref()).ok()?;
let path = key.query_str(ver).ok()?;
Some(path.into())
}
// To find the Universal CRT we look in a specific registry key for where
// all the Universal CRTs are located and then sort them asciibetically to
// find the newest version. While this sort of sorting isn't ideal, it is
// what vcvars does so that's good enough for us.
//
// Returns a pair of (root, version) for the ucrt dir if found
fn get_ucrt_dir() -> Option<(PathBuf, String)> {
let key = r"SOFTWARE\Microsoft\Windows Kits\Installed Roots";
let key = LOCAL_MACHINE.open(key.as_ref()).ok()?;
let root = key.query_str("KitsRoot10").ok()?;
let readdir = Path::new(&root).join("lib").read_dir().ok()?;
let max_libdir = readdir
.filter_map(|dir| dir.ok())
.map(|dir| dir.path())
.filter(|dir| {
dir.components()
.last()
.and_then(|c| c.as_os_str().to_str())
.map(|c| c.starts_with("10.") && dir.join("ucrt").is_dir())
.unwrap_or(false)
})
.max()?;
let version = max_libdir.components().last().unwrap();
let version = version.as_os_str().to_str().unwrap().to_string();
Some((root.into(), version))
}
// Vcvars finds the correct version of the Windows 10 SDK by looking
// for the include `um\Windows.h` because sometimes a given version will
// only have UCRT bits without the rest of the SDK. Since we only care about
// libraries and not includes, we instead look for `um\x64\kernel32.lib`.
// Since the 32-bit and 64-bit libraries are always installed together we
// only need to bother checking x64, making this code a tiny bit simpler.
// Like we do for the Universal CRT, we sort the possibilities
// asciibetically to find the newest one as that is what vcvars does.
// Before doing that, we check the "WindowsSdkDir" and "WindowsSDKVersion"
// environment variables set by vcvars to use the environment sdk version
// if one is already configured.
fn get_sdk10_dir() -> Option<(PathBuf, String)> {
if let (Ok(root), Ok(version)) = (env::var("WindowsSdkDir"), env::var("WindowsSDKVersion"))
{
return Some((root.into(), version.trim_end_matches('\\').to_string()));
}
let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0";
let key = LOCAL_MACHINE.open(key.as_ref()).ok()?;
let root = key.query_str("InstallationFolder").ok()?;
let readdir = Path::new(&root).join("lib").read_dir().ok()?;
let mut dirs = readdir
.filter_map(|dir| dir.ok())
.map(|dir| dir.path())
.collect::<Vec<_>>();
dirs.sort();
let dir = dirs
.into_iter()
.rev()
.filter(|dir| dir.join("um").join("x64").join("kernel32.lib").is_file())
.next()?;
let version = dir.components().last().unwrap();
let version = version.as_os_str().to_str().unwrap().to_string();
Some((root.into(), version))
}
// Interestingly there are several subdirectories, `win7` `win8` and
// `winv6.3`. Vcvars seems to only care about `winv6.3` though, so the same
// applies to us. Note that if we were targeting kernel mode drivers
// instead of user mode applications, we would care.
fn get_sdk81_dir() -> Option<PathBuf> {
let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.1";
let key = LOCAL_MACHINE.open(key.as_ref()).ok()?;
let root = key.query_str("InstallationFolder").ok()?;
Some(root.into())
}
fn get_sdk8_dir() -> Option<PathBuf> {
let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.0";
let key = LOCAL_MACHINE.open(key.as_ref()).ok()?;
let root = key.query_str("InstallationFolder").ok()?;
Some(root.into())
}
const PROCESSOR_ARCHITECTURE_INTEL: u16 = 0;
const PROCESSOR_ARCHITECTURE_AMD64: u16 = 9;
const PROCESSOR_ARCHITECTURE_ARM64: u16 = 12;
const X86: u16 = PROCESSOR_ARCHITECTURE_INTEL;
const X86_64: u16 = PROCESSOR_ARCHITECTURE_AMD64;
const AARCH64: u16 = PROCESSOR_ARCHITECTURE_ARM64;
// When choosing the tool to use, we have to choose the one which matches
// the target architecture. Otherwise we end up in situations where someone
// on 32-bit Windows is trying to cross compile to 64-bit and it tries to
// invoke the native 64-bit compiler which won't work.
//
// For the return value of this function, the first member of the tuple is
// the folder of the tool we will be invoking, while the second member is
// the folder of the host toolchain for that tool which is essential when
// using a cross linker. We return a Vec since on x64 there are often two
// linkers that can target the architecture we desire. The 64-bit host
// linker is preferred, and hence first, due to 64-bit allowing it more
// address space to work with and potentially being faster.
fn bin_subdir(target: &str) -> Vec<(&'static str, &'static str)> {
let arch = target.split('-').next().unwrap();
match (arch, host_arch()) {
("i586", X86) | ("i686", X86) => vec![("", "")],
("i586", X86_64) | ("i686", X86_64) => vec![("amd64_x86", "amd64"), ("", "")],
("x86_64", X86) => vec![("x86_amd64", "")],
("x86_64", X86_64) => vec![("amd64", "amd64"), ("x86_amd64", "")],
("arm", X86) | ("thumbv7a", X86) => vec![("x86_arm", "")],
("arm", X86_64) | ("thumbv7a", X86_64) => vec![("amd64_arm", "amd64"), ("x86_arm", "")],
_ => vec![],
}
}
fn lib_subdir(target: &str) -> Option<&'static str> {
let arch = target.split('-').next().unwrap();
match arch {
"i586" | "i686" => Some("x86"),
"x86_64" => Some("x64"),
"arm" | "thumbv7a" => Some("arm"),
"aarch64" => Some("arm64"),
_ => None,
}
}
// MSVC's x86 libraries are not in a subfolder
fn vc_lib_subdir(target: &str) -> Option<&'static str> {
let arch = target.split('-').next().unwrap();
match arch {
"i586" | "i686" => Some(""),
"x86_64" => Some("amd64"),
"arm" | "thumbv7a" => Some("arm"),
"aarch64" => Some("arm64"),
_ => None,
}
}
#[allow(bad_style)]
fn host_arch() -> u16 {
type DWORD = u32;
type WORD = u16;
type LPVOID = *mut u8;
type DWORD_PTR = usize;
#[repr(C)]
struct SYSTEM_INFO {
wProcessorArchitecture: WORD,
_wReserved: WORD,
_dwPageSize: DWORD,
_lpMinimumApplicationAddress: LPVOID,
_lpMaximumApplicationAddress: LPVOID,
_dwActiveProcessorMask: DWORD_PTR,
_dwNumberOfProcessors: DWORD,
_dwProcessorType: DWORD,
_dwAllocationGranularity: DWORD,
_wProcessorLevel: WORD,
_wProcessorRevision: WORD,
}
extern "system" {
fn GetNativeSystemInfo(lpSystemInfo: *mut SYSTEM_INFO);
}
unsafe {
let mut info = mem::zeroed();
GetNativeSystemInfo(&mut info);
info.wProcessorArchitecture
}
}
// Given a registry key, look at all the sub keys and find the one which has
// the maximal numeric value.
//
// Returns the name of the maximal key as well as the opened maximal key.
fn max_version(key: &RegistryKey) -> Option<(OsString, RegistryKey)> {
let mut max_vers = 0;
let mut max_key = None;
for subkey in key.iter().filter_map(|k| k.ok()) {
let val = subkey
.to_str()
.and_then(|s| s.trim_left_matches("v").replace(".", "").parse().ok());
let val = match val {
Some(s) => s,
None => continue,
};
if val > max_vers {
if let Ok(k) = key.open(&subkey) {
max_vers = val;
max_key = Some((subkey, k));
}
}
}
max_key
}
pub fn has_msbuild_version(version: &str) -> bool {
match version {
"17.0" => {
find_msbuild_vs17("x86_64-pc-windows-msvc").is_some()
|| find_msbuild_vs17("i686-pc-windows-msvc").is_some()
|| find_msbuild_vs17("aarch64-pc-windows-msvc").is_some()
}
"16.0" => {
find_msbuild_vs16("x86_64-pc-windows-msvc").is_some()
|| find_msbuild_vs16("i686-pc-windows-msvc").is_some()
|| find_msbuild_vs16("aarch64-pc-windows-msvc").is_some()
}
"15.0" => {
find_msbuild_vs15("x86_64-pc-windows-msvc").is_some()
|| find_msbuild_vs15("i686-pc-windows-msvc").is_some()
|| find_msbuild_vs15("aarch64-pc-windows-msvc").is_some()
}
"12.0" | "14.0" => LOCAL_MACHINE
.open(&OsString::from(format!(
"SOFTWARE\\Microsoft\\MSBuild\\ToolsVersions\\{}",
version
)))
.is_ok(),
_ => false,
}
}
pub fn find_devenv(target: &str) -> Option<Tool> {
find_devenv_vs15(&target)
}
fn find_devenv_vs15(target: &str) -> Option<Tool> {
find_tool_in_vs15_path(r"Common7\IDE\devenv.exe", target)
}
// see http://stackoverflow.com/questions/328017/path-to-msbuild
pub fn find_msbuild(target: &str) -> Option<Tool> {
// VS 15 (2017) changed how to locate msbuild
if let Some(r) = find_msbuild_vs17(target) {
return Some(r);
} else if let Some(r) = find_msbuild_vs16(target) {
return Some(r);
} else if let Some(r) = find_msbuild_vs15(target) {
return Some(r);
} else {
find_old_msbuild(target)
}
}
fn find_msbuild_vs15(target: &str) -> Option<Tool> {
find_tool_in_vs15_path(r"MSBuild\15.0\Bin\MSBuild.exe", target)
}
fn find_old_msbuild(target: &str) -> Option<Tool> {
let key = r"SOFTWARE\Microsoft\MSBuild\ToolsVersions";
LOCAL_MACHINE
.open(key.as_ref())
.ok()
.and_then(|key| {
max_version(&key).and_then(|(_vers, key)| key.query_str("MSBuildToolsPath").ok())
})
.map(|path| {
let mut path = PathBuf::from(path);
path.push("MSBuild.exe");
let mut tool = Tool::with_family(path, MSVC_FAMILY);
if target.contains("x86_64") {
tool.env.push(("Platform".into(), "X64".into()));
}
tool
})
}
}

198
vendor/cc/src/windows_sys.rs vendored Normal file
View File

@ -0,0 +1,198 @@
// This file is autogenerated.
//
// To add bindings, edit windows_sys.lst then run:
//
// ```
// cd generate-windows-sys/
// cargo run
// ```
// Bindings generated by `windows-bindgen` 0.49.0
#![allow(
non_snake_case,
non_upper_case_globals,
non_camel_case_types,
dead_code,
clippy::all
)]
#[link(name = "advapi32")]
extern "system" {
pub fn RegCloseKey(hkey: HKEY) -> WIN32_ERROR;
}
#[link(name = "advapi32")]
extern "system" {
pub fn RegEnumKeyExW(
hkey: HKEY,
dwindex: u32,
lpname: PWSTR,
lpcchname: *mut u32,
lpreserved: *const u32,
lpclass: PWSTR,
lpcchclass: *mut u32,
lpftlastwritetime: *mut FILETIME,
) -> WIN32_ERROR;
}
#[link(name = "advapi32")]
extern "system" {
pub fn RegOpenKeyExW(
hkey: HKEY,
lpsubkey: PCWSTR,
uloptions: u32,
samdesired: REG_SAM_FLAGS,
phkresult: *mut HKEY,
) -> WIN32_ERROR;
}
#[link(name = "advapi32")]
extern "system" {
pub fn RegQueryValueExW(
hkey: HKEY,
lpvaluename: PCWSTR,
lpreserved: *const u32,
lptype: *mut REG_VALUE_TYPE,
lpdata: *mut u8,
lpcbdata: *mut u32,
) -> WIN32_ERROR;
}
#[link(name = "kernel32")]
extern "system" {
pub fn CreatePipe(
hreadpipe: *mut HANDLE,
hwritepipe: *mut HANDLE,
lppipeattributes: *const SECURITY_ATTRIBUTES,
nsize: u32,
) -> BOOL;
}
#[link(name = "ole32")]
extern "system" {
pub fn CoCreateInstance(
rclsid: *const GUID,
punkouter: IUnknown,
dwclscontext: CLSCTX,
riid: *const GUID,
ppv: *mut *mut ::core::ffi::c_void,
) -> HRESULT;
}
#[link(name = "ole32")]
extern "system" {
pub fn CoInitializeEx(pvreserved: *const ::core::ffi::c_void, dwcoinit: COINIT) -> HRESULT;
}
#[link(name = "oleaut32")]
extern "system" {
pub fn SysFreeString(bstrstring: BSTR) -> ();
}
#[link(name = "oleaut32")]
extern "system" {
pub fn SysStringLen(pbstr: BSTR) -> u32;
}
pub type ADVANCED_FEATURE_FLAGS = u16;
pub type BOOL = i32;
pub type BSTR = *const u16;
pub type CLSCTX = u32;
pub const CLSCTX_ALL: CLSCTX = 23u32;
pub type COINIT = i32;
pub const COINIT_MULTITHREADED: COINIT = 0i32;
pub const ERROR_NO_MORE_ITEMS: WIN32_ERROR = 259u32;
pub const ERROR_SUCCESS: WIN32_ERROR = 0u32;
#[repr(C)]
pub struct FILETIME {
pub dwLowDateTime: u32,
pub dwHighDateTime: u32,
}
impl ::core::marker::Copy for FILETIME {}
impl ::core::clone::Clone for FILETIME {
fn clone(&self) -> Self {
*self
}
}
#[repr(C)]
pub struct GUID {
pub data1: u32,
pub data2: u16,
pub data3: u16,
pub data4: [u8; 8],
}
impl GUID {
pub const fn from_u128(uuid: u128) -> Self {
Self {
data1: (uuid >> 96) as u32,
data2: (uuid >> 80 & 0xffff) as u16,
data3: (uuid >> 64 & 0xffff) as u16,
data4: (uuid as u64).to_be_bytes(),
}
}
}
impl ::core::marker::Copy for GUID {}
impl ::core::clone::Clone for GUID {
fn clone(&self) -> Self {
*self
}
}
pub type HANDLE = *mut ::core::ffi::c_void;
pub type HKEY = *mut ::core::ffi::c_void;
pub const HKEY_LOCAL_MACHINE: HKEY = invalid_mut(-2147483646i32 as _);
pub type HRESULT = i32;
pub const INVALID_HANDLE_VALUE: HANDLE = invalid_mut(-1i32 as _);
pub type IUnknown = *mut ::core::ffi::c_void;
pub const KEY_READ: REG_SAM_FLAGS = 131097u32;
pub const KEY_WOW64_32KEY: REG_SAM_FLAGS = 512u32;
pub type PCWSTR = *const u16;
pub type PWSTR = *mut u16;
pub type REG_SAM_FLAGS = u32;
pub const REG_SZ: REG_VALUE_TYPE = 1u32;
pub type REG_VALUE_TYPE = u32;
#[repr(C)]
pub struct SAFEARRAY {
pub cDims: u16,
pub fFeatures: ADVANCED_FEATURE_FLAGS,
pub cbElements: u32,
pub cLocks: u32,
pub pvData: *mut ::core::ffi::c_void,
pub rgsabound: [SAFEARRAYBOUND; 1],
}
impl ::core::marker::Copy for SAFEARRAY {}
impl ::core::clone::Clone for SAFEARRAY {
fn clone(&self) -> Self {
*self
}
}
#[repr(C)]
pub struct SAFEARRAYBOUND {
pub cElements: u32,
pub lLbound: i32,
}
impl ::core::marker::Copy for SAFEARRAYBOUND {}
impl ::core::clone::Clone for SAFEARRAYBOUND {
fn clone(&self) -> Self {
*self
}
}
#[repr(C)]
pub struct SECURITY_ATTRIBUTES {
pub nLength: u32,
pub lpSecurityDescriptor: *mut ::core::ffi::c_void,
pub bInheritHandle: BOOL,
}
impl ::core::marker::Copy for SECURITY_ATTRIBUTES {}
impl ::core::clone::Clone for SECURITY_ATTRIBUTES {
fn clone(&self) -> Self {
*self
}
}
pub const S_FALSE: HRESULT = 1i32;
pub const S_OK: HRESULT = 0i32;
pub type WIN32_ERROR = u32;
/// Adapted from
/// [`core::ptr::invalid_mut()`](https://doc.rust-lang.org/src/core/ptr/mod.rs.html#600-607).
///
/// This function should actually use `core::mem::transmute` but due to msrv
/// we use `as` casting instead.
///
/// Once msrv is bumped to 1.56, replace this with `core::mem::transmute` since
/// it is const stablised in 1.56
///
/// NOTE that once supports `strict_provenance` we would also have to update
/// this.
const fn invalid_mut<T>(addr: usize) -> *mut T {
addr as *mut T
}