Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
433
third-party/vendor/cc/src/command_helpers.rs
vendored
Normal file
433
third-party/vendor/cc/src/command_helpers.rs
vendored
Normal file
|
|
@ -0,0 +1,433 @@
|
|||
//! Miscellaneous helpers for running commands
|
||||
|
||||
use std::{
|
||||
collections::hash_map,
|
||||
ffi::OsString,
|
||||
fmt::Display,
|
||||
fs,
|
||||
hash::Hasher,
|
||||
io::{self, Read, Write},
|
||||
path::Path,
|
||||
process::{Child, ChildStderr, Command, Stdio},
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Arc,
|
||||
},
|
||||
};
|
||||
|
||||
use crate::{Error, ErrorKind, Object};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct CargoOutput {
|
||||
pub(crate) metadata: bool,
|
||||
pub(crate) warnings: bool,
|
||||
pub(crate) debug: bool,
|
||||
checked_dbg_var: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
impl CargoOutput {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
metadata: true,
|
||||
warnings: true,
|
||||
debug: std::env::var_os("CC_ENABLE_DEBUG_OUTPUT").is_some(),
|
||||
checked_dbg_var: Arc::new(AtomicBool::new(false)),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn print_metadata(&self, s: &dyn Display) {
|
||||
if self.metadata {
|
||||
println!("{}", s);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn print_warning(&self, arg: &dyn Display) {
|
||||
if self.warnings {
|
||||
println!("cargo:warning={}", arg);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn print_debug(&self, arg: &dyn Display) {
|
||||
if self.metadata && !self.checked_dbg_var.load(Ordering::Relaxed) {
|
||||
self.checked_dbg_var.store(true, Ordering::Relaxed);
|
||||
println!("cargo:rerun-if-env-changed=CC_ENABLE_DEBUG_OUTPUT");
|
||||
}
|
||||
if self.debug {
|
||||
println!("{}", arg);
|
||||
}
|
||||
}
|
||||
|
||||
fn stdio_for_warnings(&self) -> Stdio {
|
||||
if self.warnings {
|
||||
Stdio::piped()
|
||||
} else {
|
||||
Stdio::null()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct StderrForwarder {
|
||||
inner: Option<(ChildStderr, Vec<u8>)>,
|
||||
#[cfg(feature = "parallel")]
|
||||
is_non_blocking: bool,
|
||||
#[cfg(feature = "parallel")]
|
||||
bytes_available_failed: bool,
|
||||
}
|
||||
|
||||
const MIN_BUFFER_CAPACITY: usize = 100;
|
||||
|
||||
impl StderrForwarder {
|
||||
pub(crate) fn new(child: &mut Child) -> Self {
|
||||
Self {
|
||||
inner: child
|
||||
.stderr
|
||||
.take()
|
||||
.map(|stderr| (stderr, Vec::with_capacity(MIN_BUFFER_CAPACITY))),
|
||||
#[cfg(feature = "parallel")]
|
||||
is_non_blocking: false,
|
||||
#[cfg(feature = "parallel")]
|
||||
bytes_available_failed: false,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::uninit_vec)]
|
||||
fn forward_available(&mut self) -> bool {
|
||||
if let Some((stderr, buffer)) = self.inner.as_mut() {
|
||||
loop {
|
||||
let old_data_end = buffer.len();
|
||||
|
||||
// For non-blocking we check to see if there is data available, so we should try to
|
||||
// read at least that much. For blocking, always read at least the minimum amount.
|
||||
#[cfg(not(feature = "parallel"))]
|
||||
let to_reserve = MIN_BUFFER_CAPACITY;
|
||||
#[cfg(feature = "parallel")]
|
||||
let to_reserve = if self.is_non_blocking && !self.bytes_available_failed {
|
||||
match crate::parallel::stderr::bytes_available(stderr) {
|
||||
#[cfg(windows)]
|
||||
Ok(0) => return false,
|
||||
#[cfg(unix)]
|
||||
Ok(0) => {
|
||||
// On Unix, depending on the implementation, we may sometimes get 0 in a
|
||||
// loop (either there is data available or the pipe is broken), so
|
||||
// continue with the non-blocking read anyway.
|
||||
MIN_BUFFER_CAPACITY
|
||||
}
|
||||
#[cfg(windows)]
|
||||
Err(_) => {
|
||||
// On Windows, if we get an error then the pipe is broken, so flush
|
||||
// the buffer and bail.
|
||||
if !buffer.is_empty() {
|
||||
write_warning(&buffer[..]);
|
||||
}
|
||||
self.inner = None;
|
||||
return true;
|
||||
}
|
||||
#[cfg(unix)]
|
||||
Err(_) => {
|
||||
// On Unix, depending on the implementation, we may get spurious
|
||||
// errors so make a note not to use bytes_available again and try
|
||||
// the non-blocking read anyway.
|
||||
self.bytes_available_failed = true;
|
||||
MIN_BUFFER_CAPACITY
|
||||
}
|
||||
Ok(bytes_available) => MIN_BUFFER_CAPACITY.max(bytes_available),
|
||||
}
|
||||
} else {
|
||||
MIN_BUFFER_CAPACITY
|
||||
};
|
||||
buffer.reserve(to_reserve);
|
||||
|
||||
// SAFETY: 1) the length is set to the capacity, so we are never using memory beyond
|
||||
// the underlying buffer and 2) we always call `truncate` below to set the len back
|
||||
// to the initialized data.
|
||||
unsafe {
|
||||
buffer.set_len(buffer.capacity());
|
||||
}
|
||||
match stderr.read(&mut buffer[old_data_end..]) {
|
||||
Err(err) if err.kind() == std::io::ErrorKind::WouldBlock => {
|
||||
// No data currently, yield back.
|
||||
buffer.truncate(old_data_end);
|
||||
return false;
|
||||
}
|
||||
Err(err) if err.kind() == std::io::ErrorKind::Interrupted => {
|
||||
// Interrupted, try again.
|
||||
buffer.truncate(old_data_end);
|
||||
}
|
||||
Ok(0) | Err(_) => {
|
||||
// End of stream: flush remaining data and bail.
|
||||
if old_data_end > 0 {
|
||||
write_warning(&buffer[..old_data_end]);
|
||||
}
|
||||
self.inner = None;
|
||||
return true;
|
||||
}
|
||||
Ok(bytes_read) => {
|
||||
buffer.truncate(old_data_end + bytes_read);
|
||||
let mut consumed = 0;
|
||||
for line in buffer.split_inclusive(|&b| b == b'\n') {
|
||||
// Only forward complete lines, leave the rest in the buffer.
|
||||
if let Some((b'\n', line)) = line.split_last() {
|
||||
consumed += line.len() + 1;
|
||||
write_warning(line);
|
||||
}
|
||||
}
|
||||
buffer.drain(..consumed);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "parallel")]
|
||||
pub(crate) fn set_non_blocking(&mut self) -> Result<(), Error> {
|
||||
assert!(!self.is_non_blocking);
|
||||
|
||||
#[cfg(unix)]
|
||||
if let Some((stderr, _)) = self.inner.as_ref() {
|
||||
crate::parallel::stderr::set_non_blocking(stderr)?;
|
||||
}
|
||||
|
||||
self.is_non_blocking = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "parallel")]
|
||||
fn forward_all(&mut self) {
|
||||
while !self.forward_available() {}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "parallel"))]
|
||||
fn forward_all(&mut self) {
|
||||
let forward_result = self.forward_available();
|
||||
assert!(forward_result, "Should have consumed all data");
|
||||
}
|
||||
}
|
||||
|
||||
fn write_warning(line: &[u8]) {
|
||||
let stdout = io::stdout();
|
||||
let mut stdout = stdout.lock();
|
||||
stdout.write_all(b"cargo:warning=").unwrap();
|
||||
stdout.write_all(line).unwrap();
|
||||
stdout.write_all(b"\n").unwrap();
|
||||
}
|
||||
|
||||
fn wait_on_child(
|
||||
cmd: &Command,
|
||||
program: &str,
|
||||
child: &mut Child,
|
||||
cargo_output: &CargoOutput,
|
||||
) -> Result<(), Error> {
|
||||
StderrForwarder::new(child).forward_all();
|
||||
|
||||
let status = match child.wait() {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
return Err(Error::new(
|
||||
ErrorKind::ToolExecError,
|
||||
format!(
|
||||
"Failed to wait on spawned child process, command {:?} with args {:?}: {}.",
|
||||
cmd, program, e
|
||||
),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
cargo_output.print_debug(&status);
|
||||
|
||||
if status.success() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::new(
|
||||
ErrorKind::ToolExecError,
|
||||
format!(
|
||||
"Command {:?} with args {:?} did not execute successfully (status code {}).",
|
||||
cmd, program, status
|
||||
),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// Find the destination object path for each file in the input source files,
|
||||
/// and store them in the output Object.
|
||||
pub(crate) fn objects_from_files(files: &[Arc<Path>], dst: &Path) -> Result<Vec<Object>, Error> {
|
||||
let mut objects = Vec::with_capacity(files.len());
|
||||
for file in files {
|
||||
let basename = file
|
||||
.file_name()
|
||||
.ok_or_else(|| {
|
||||
Error::new(
|
||||
ErrorKind::InvalidArgument,
|
||||
"No file_name for object file path!",
|
||||
)
|
||||
})?
|
||||
.to_string_lossy();
|
||||
let dirname = file
|
||||
.parent()
|
||||
.ok_or_else(|| {
|
||||
Error::new(
|
||||
ErrorKind::InvalidArgument,
|
||||
"No parent for object file path!",
|
||||
)
|
||||
})?
|
||||
.to_string_lossy();
|
||||
|
||||
// Hash the dirname. This should prevent conflicts if we have multiple
|
||||
// object files with the same filename in different subfolders.
|
||||
let mut hasher = hash_map::DefaultHasher::new();
|
||||
hasher.write(dirname.to_string().as_bytes());
|
||||
let obj = dst
|
||||
.join(format!("{:016x}-{}", hasher.finish(), basename))
|
||||
.with_extension("o");
|
||||
|
||||
match obj.parent() {
|
||||
Some(s) => fs::create_dir_all(s)?,
|
||||
None => {
|
||||
return Err(Error::new(
|
||||
ErrorKind::InvalidArgument,
|
||||
"dst is an invalid path with no parent",
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
objects.push(Object::new(file.to_path_buf(), obj));
|
||||
}
|
||||
|
||||
Ok(objects)
|
||||
}
|
||||
|
||||
pub(crate) fn run(
|
||||
cmd: &mut Command,
|
||||
program: &str,
|
||||
cargo_output: &CargoOutput,
|
||||
) -> Result<(), Error> {
|
||||
let mut child = spawn(cmd, program, cargo_output)?;
|
||||
wait_on_child(cmd, program, &mut child, cargo_output)
|
||||
}
|
||||
|
||||
pub(crate) fn run_output(
|
||||
cmd: &mut Command,
|
||||
program: &str,
|
||||
cargo_output: &CargoOutput,
|
||||
) -> Result<Vec<u8>, Error> {
|
||||
cmd.stdout(Stdio::piped());
|
||||
|
||||
let mut child = spawn(cmd, program, cargo_output)?;
|
||||
|
||||
let mut stdout = vec![];
|
||||
child
|
||||
.stdout
|
||||
.take()
|
||||
.unwrap()
|
||||
.read_to_end(&mut stdout)
|
||||
.unwrap();
|
||||
|
||||
wait_on_child(cmd, program, &mut child, cargo_output)?;
|
||||
|
||||
Ok(stdout)
|
||||
}
|
||||
|
||||
pub(crate) fn spawn(
|
||||
cmd: &mut Command,
|
||||
program: &str,
|
||||
cargo_output: &CargoOutput,
|
||||
) -> Result<Child, Error> {
|
||||
struct ResetStderr<'cmd>(&'cmd mut Command);
|
||||
|
||||
impl Drop for ResetStderr<'_> {
|
||||
fn drop(&mut self) {
|
||||
// Reset stderr to default to release pipe_writer so that print thread will
|
||||
// not block forever.
|
||||
self.0.stderr(Stdio::inherit());
|
||||
}
|
||||
}
|
||||
|
||||
cargo_output.print_debug(&format_args!("running: {:?}", cmd));
|
||||
|
||||
let cmd = ResetStderr(cmd);
|
||||
let child = cmd.0.stderr(cargo_output.stdio_for_warnings()).spawn();
|
||||
match child {
|
||||
Ok(child) => Ok(child),
|
||||
Err(ref e) if e.kind() == io::ErrorKind::NotFound => {
|
||||
let extra = if cfg!(windows) {
|
||||
" (see https://github.com/rust-lang/cc-rs#compile-time-requirements \
|
||||
for help)"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
Err(Error::new(
|
||||
ErrorKind::ToolNotFound,
|
||||
format!("Failed to find tool. Is `{}` installed?{}", program, extra),
|
||||
))
|
||||
}
|
||||
Err(e) => Err(Error::new(
|
||||
ErrorKind::ToolExecError,
|
||||
format!(
|
||||
"Command {:?} with args {:?} failed to start: {:?}",
|
||||
cmd.0, program, e
|
||||
),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn command_add_output_file(
|
||||
cmd: &mut Command,
|
||||
dst: &Path,
|
||||
cuda: bool,
|
||||
msvc: bool,
|
||||
clang: bool,
|
||||
gnu: bool,
|
||||
is_asm: bool,
|
||||
is_arm: bool,
|
||||
) {
|
||||
if msvc && !clang && !gnu && !cuda && !(is_asm && is_arm) {
|
||||
let mut s = OsString::from("-Fo");
|
||||
s.push(dst);
|
||||
cmd.arg(s);
|
||||
} else {
|
||||
cmd.arg("-o").arg(dst);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "parallel")]
|
||||
pub(crate) fn try_wait_on_child(
|
||||
cmd: &Command,
|
||||
program: &str,
|
||||
child: &mut Child,
|
||||
stdout: &mut dyn io::Write,
|
||||
stderr_forwarder: &mut StderrForwarder,
|
||||
) -> Result<Option<()>, Error> {
|
||||
stderr_forwarder.forward_available();
|
||||
|
||||
match child.try_wait() {
|
||||
Ok(Some(status)) => {
|
||||
stderr_forwarder.forward_all();
|
||||
|
||||
let _ = writeln!(stdout, "{}", status);
|
||||
|
||||
if status.success() {
|
||||
Ok(Some(()))
|
||||
} else {
|
||||
Err(Error::new(
|
||||
ErrorKind::ToolExecError,
|
||||
format!(
|
||||
"Command {:?} with args {:?} did not execute successfully (status code {}).",
|
||||
cmd, program, status
|
||||
),
|
||||
))
|
||||
}
|
||||
}
|
||||
Ok(None) => Ok(None),
|
||||
Err(e) => {
|
||||
stderr_forwarder.forward_all();
|
||||
Err(Error::new(
|
||||
ErrorKind::ToolExecError,
|
||||
format!(
|
||||
"Failed to wait on spawned child process, command {:?} with args {:?}: {}.",
|
||||
cmd, program, e
|
||||
),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
3982
third-party/vendor/cc/src/lib.rs
vendored
Normal file
3982
third-party/vendor/cc/src/lib.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
118
third-party/vendor/cc/src/parallel/async_executor.rs
vendored
Normal file
118
third-party/vendor/cc/src/parallel/async_executor.rs
vendored
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
use std::{
|
||||
cell::Cell,
|
||||
future::Future,
|
||||
pin::Pin,
|
||||
ptr,
|
||||
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
|
||||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use crate::Error;
|
||||
|
||||
const NOOP_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(
|
||||
// Cloning just returns a new no-op raw waker
|
||||
|_| NOOP_RAW_WAKER,
|
||||
// `wake` does nothing
|
||||
|_| {},
|
||||
// `wake_by_ref` does nothing
|
||||
|_| {},
|
||||
// Dropping does nothing as we don't allocate anything
|
||||
|_| {},
|
||||
);
|
||||
const NOOP_RAW_WAKER: RawWaker = RawWaker::new(ptr::null(), &NOOP_WAKER_VTABLE);
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct YieldOnce(bool);
|
||||
|
||||
impl Future for YieldOnce {
|
||||
type Output = ();
|
||||
|
||||
fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<()> {
|
||||
let flag = &mut std::pin::Pin::into_inner(self).0;
|
||||
if !*flag {
|
||||
*flag = true;
|
||||
Poll::Pending
|
||||
} else {
|
||||
Poll::Ready(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Execute the futures and return when they are all done.
|
||||
///
|
||||
/// Here we use our own homebrew async executor since cc is used in the build
|
||||
/// script of many popular projects, pulling in additional dependencies would
|
||||
/// significantly slow down its compilation.
|
||||
pub(crate) fn block_on<Fut1, Fut2>(
|
||||
mut fut1: Fut1,
|
||||
mut fut2: Fut2,
|
||||
has_made_progress: &Cell<bool>,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
Fut1: Future<Output = Result<(), Error>>,
|
||||
Fut2: Future<Output = Result<(), Error>>,
|
||||
{
|
||||
// Shadows the future so that it can never be moved and is guaranteed
|
||||
// to be pinned.
|
||||
//
|
||||
// The same trick used in `pin!` macro.
|
||||
//
|
||||
// TODO: Once MSRV is bumped to 1.68, replace this with `std::pin::pin!`
|
||||
let mut fut1 = Some(unsafe { Pin::new_unchecked(&mut fut1) });
|
||||
let mut fut2 = Some(unsafe { Pin::new_unchecked(&mut fut2) });
|
||||
|
||||
// TODO: Once `Waker::noop` stablised and our MSRV is bumped to the version
|
||||
// which it is stablised, replace this with `Waker::noop`.
|
||||
let waker = unsafe { Waker::from_raw(NOOP_RAW_WAKER) };
|
||||
let mut context = Context::from_waker(&waker);
|
||||
|
||||
let mut backoff_cnt = 0;
|
||||
|
||||
loop {
|
||||
has_made_progress.set(false);
|
||||
|
||||
if let Some(fut) = fut2.as_mut() {
|
||||
if let Poll::Ready(res) = fut.as_mut().poll(&mut context) {
|
||||
fut2 = None;
|
||||
res?;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(fut) = fut1.as_mut() {
|
||||
if let Poll::Ready(res) = fut.as_mut().poll(&mut context) {
|
||||
fut1 = None;
|
||||
res?;
|
||||
}
|
||||
}
|
||||
|
||||
if fut1.is_none() && fut2.is_none() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if !has_made_progress.get() {
|
||||
if backoff_cnt > 3 {
|
||||
// We have yielded at least three times without making'
|
||||
// any progress, so we will sleep for a while.
|
||||
let duration = Duration::from_millis(100 * (backoff_cnt - 3).min(10));
|
||||
thread::sleep(duration);
|
||||
} else {
|
||||
// Given that we spawned a lot of compilation tasks, it is unlikely
|
||||
// that OS cannot find other ready task to execute.
|
||||
//
|
||||
// If all of them are done, then we will yield them and spawn more,
|
||||
// or simply return.
|
||||
//
|
||||
// Thus this will not be turned into a busy-wait loop and it will not
|
||||
// waste CPU resource.
|
||||
thread::yield_now();
|
||||
}
|
||||
}
|
||||
|
||||
backoff_cnt = if has_made_progress.get() {
|
||||
0
|
||||
} else {
|
||||
backoff_cnt + 1
|
||||
};
|
||||
}
|
||||
}
|
||||
255
third-party/vendor/cc/src/parallel/job_token.rs
vendored
Normal file
255
third-party/vendor/cc/src/parallel/job_token.rs
vendored
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
use std::{marker::PhantomData, mem::MaybeUninit, sync::Once};
|
||||
|
||||
use crate::Error;
|
||||
|
||||
pub(crate) struct JobToken(PhantomData<()>);
|
||||
|
||||
impl JobToken {
|
||||
fn new() -> Self {
|
||||
Self(PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for JobToken {
|
||||
fn drop(&mut self) {
|
||||
match JobTokenServer::new() {
|
||||
JobTokenServer::Inherited(jobserver) => jobserver.release_token_raw(),
|
||||
JobTokenServer::InProcess(jobserver) => jobserver.release_token_raw(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum JobTokenServer {
|
||||
Inherited(inherited_jobserver::JobServer),
|
||||
InProcess(inprocess_jobserver::JobServer),
|
||||
}
|
||||
|
||||
impl JobTokenServer {
|
||||
/// This function returns a static reference to the jobserver because
|
||||
/// - creating a jobserver from env is a bit fd-unsafe (e.g. the fd might
|
||||
/// be closed by other jobserver users in the process) and better do it
|
||||
/// at the start of the program.
|
||||
/// - in case a jobserver cannot be created from env (e.g. it's not
|
||||
/// present), we will create a global in-process only jobserver
|
||||
/// that has to be static so that it will be shared by all cc
|
||||
/// compilation.
|
||||
fn new() -> &'static Self {
|
||||
static INIT: Once = Once::new();
|
||||
static mut JOBSERVER: MaybeUninit<JobTokenServer> = MaybeUninit::uninit();
|
||||
|
||||
unsafe {
|
||||
INIT.call_once(|| {
|
||||
let server = inherited_jobserver::JobServer::from_env()
|
||||
.map(Self::Inherited)
|
||||
.unwrap_or_else(|| Self::InProcess(inprocess_jobserver::JobServer::new()));
|
||||
JOBSERVER = MaybeUninit::new(server);
|
||||
});
|
||||
// TODO: Poor man's assume_init_ref, as that'd require a MSRV of 1.55.
|
||||
&*JOBSERVER.as_ptr()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) enum ActiveJobTokenServer {
|
||||
Inherited(inherited_jobserver::ActiveJobServer<'static>),
|
||||
InProcess(&'static inprocess_jobserver::JobServer),
|
||||
}
|
||||
|
||||
impl ActiveJobTokenServer {
|
||||
pub(crate) fn new() -> Result<Self, Error> {
|
||||
match JobTokenServer::new() {
|
||||
JobTokenServer::Inherited(inherited_jobserver) => {
|
||||
inherited_jobserver.enter_active().map(Self::Inherited)
|
||||
}
|
||||
JobTokenServer::InProcess(inprocess_jobserver) => {
|
||||
Ok(Self::InProcess(inprocess_jobserver))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn acquire(&self) -> Result<JobToken, Error> {
|
||||
match &self {
|
||||
Self::Inherited(jobserver) => jobserver.acquire().await,
|
||||
Self::InProcess(jobserver) => Ok(jobserver.acquire().await),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod inherited_jobserver {
|
||||
use super::JobToken;
|
||||
|
||||
use crate::{parallel::async_executor::YieldOnce, Error, ErrorKind};
|
||||
|
||||
use std::{
|
||||
io, mem,
|
||||
sync::{mpsc, Mutex, MutexGuard, PoisonError},
|
||||
};
|
||||
|
||||
pub(super) struct JobServer {
|
||||
/// Implicit token for this process which is obtained and will be
|
||||
/// released in parent. Since JobTokens only give back what they got,
|
||||
/// there should be at most one global implicit token in the wild.
|
||||
///
|
||||
/// Since Rust does not execute any `Drop` for global variables,
|
||||
/// we can't just put it back to jobserver and then re-acquire it at
|
||||
/// the end of the process.
|
||||
///
|
||||
/// Use `Mutex` to avoid race between acquire and release.
|
||||
/// If an `AtomicBool` is used, then it's possible for:
|
||||
/// - `release_token_raw`: Tries to set `global_implicit_token` to true, but it is already
|
||||
/// set to `true`, continue to release it to jobserver
|
||||
/// - `acquire` takes the global implicit token, set `global_implicit_token` to false
|
||||
/// - `release_token_raw` now writes the token back into the jobserver, while
|
||||
/// `global_implicit_token` is `false`
|
||||
///
|
||||
/// If the program exits here, then cc effectively increases parallelism by one, which is
|
||||
/// incorrect, hence we use a `Mutex` here.
|
||||
global_implicit_token: Mutex<bool>,
|
||||
inner: jobserver::Client,
|
||||
}
|
||||
|
||||
impl JobServer {
|
||||
pub(super) unsafe fn from_env() -> Option<Self> {
|
||||
jobserver::Client::from_env().map(|inner| Self {
|
||||
inner,
|
||||
global_implicit_token: Mutex::new(true),
|
||||
})
|
||||
}
|
||||
|
||||
fn get_global_implicit_token(&self) -> MutexGuard<'_, bool> {
|
||||
self.global_implicit_token
|
||||
.lock()
|
||||
.unwrap_or_else(PoisonError::into_inner)
|
||||
}
|
||||
|
||||
/// All tokens except for the global implicit token will be put back into the jobserver
|
||||
/// immediately and they cannot be cached, since Rust does not call `Drop::drop` on
|
||||
/// global variables.
|
||||
pub(super) fn release_token_raw(&self) {
|
||||
let mut global_implicit_token = self.get_global_implicit_token();
|
||||
|
||||
if *global_implicit_token {
|
||||
// There's already a global implicit token, so this token must
|
||||
// be released back into jobserver.
|
||||
//
|
||||
// `release_raw` should not block
|
||||
let _ = self.inner.release_raw();
|
||||
} else {
|
||||
*global_implicit_token = true;
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn enter_active(&self) -> Result<ActiveJobServer<'_>, Error> {
|
||||
ActiveJobServer::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct ActiveJobServer<'a> {
|
||||
jobserver: &'a JobServer,
|
||||
helper_thread: jobserver::HelperThread,
|
||||
/// When rx is dropped, all the token stored within it will be dropped.
|
||||
rx: mpsc::Receiver<io::Result<jobserver::Acquired>>,
|
||||
}
|
||||
|
||||
impl<'a> ActiveJobServer<'a> {
|
||||
fn new(jobserver: &'a JobServer) -> Result<Self, Error> {
|
||||
let (tx, rx) = mpsc::channel();
|
||||
|
||||
Ok(Self {
|
||||
rx,
|
||||
helper_thread: jobserver.inner.clone().into_helper_thread(move |res| {
|
||||
let _ = tx.send(res);
|
||||
})?,
|
||||
jobserver,
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) async fn acquire(&self) -> Result<JobToken, Error> {
|
||||
let mut has_requested_token = false;
|
||||
|
||||
loop {
|
||||
// Fast path
|
||||
if mem::replace(&mut *self.jobserver.get_global_implicit_token(), false) {
|
||||
break Ok(JobToken::new());
|
||||
}
|
||||
|
||||
// Cold path, no global implicit token, obtain one
|
||||
match self.rx.try_recv() {
|
||||
Ok(res) => {
|
||||
let acquired = res?;
|
||||
acquired.drop_without_releasing();
|
||||
break Ok(JobToken::new());
|
||||
}
|
||||
Err(mpsc::TryRecvError::Disconnected) => {
|
||||
break Err(Error::new(
|
||||
ErrorKind::JobserverHelpThreadError,
|
||||
"jobserver help thread has returned before ActiveJobServer is dropped",
|
||||
))
|
||||
}
|
||||
Err(mpsc::TryRecvError::Empty) => {
|
||||
if !has_requested_token {
|
||||
self.helper_thread.request_token();
|
||||
has_requested_token = true;
|
||||
}
|
||||
YieldOnce::default().await
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod inprocess_jobserver {
|
||||
use super::JobToken;
|
||||
|
||||
use crate::parallel::async_executor::YieldOnce;
|
||||
|
||||
use std::{
|
||||
env::var,
|
||||
sync::atomic::{
|
||||
AtomicU32,
|
||||
Ordering::{AcqRel, Acquire},
|
||||
},
|
||||
};
|
||||
|
||||
pub(crate) struct JobServer(AtomicU32);
|
||||
|
||||
impl JobServer {
|
||||
pub(super) fn new() -> Self {
|
||||
// Use `NUM_JOBS` if set (it's configured by Cargo) and otherwise
|
||||
// just fall back to a semi-reasonable number.
|
||||
//
|
||||
// Note that we could use `num_cpus` here but it's an extra
|
||||
// dependency that will almost never be used, so
|
||||
// it's generally not too worth it.
|
||||
let mut parallelism = 4;
|
||||
// TODO: Use std::thread::available_parallelism as an upper bound
|
||||
// when MSRV is bumped.
|
||||
if let Ok(amt) = var("NUM_JOBS") {
|
||||
if let Ok(amt) = amt.parse() {
|
||||
parallelism = amt;
|
||||
}
|
||||
}
|
||||
|
||||
Self(AtomicU32::new(parallelism))
|
||||
}
|
||||
|
||||
pub(super) async fn acquire(&self) -> JobToken {
|
||||
loop {
|
||||
let res = self
|
||||
.0
|
||||
.fetch_update(AcqRel, Acquire, |tokens| tokens.checked_sub(1));
|
||||
|
||||
if res.is_ok() {
|
||||
break JobToken::new();
|
||||
}
|
||||
|
||||
YieldOnce::default().await
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn release_token_raw(&self) {
|
||||
self.0.fetch_add(1, AcqRel);
|
||||
}
|
||||
}
|
||||
}
|
||||
20
third-party/vendor/cc/src/parallel/mod.rs
vendored
Normal file
20
third-party/vendor/cc/src/parallel/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
pub(crate) mod async_executor;
|
||||
pub(crate) mod job_token;
|
||||
pub(crate) mod stderr;
|
||||
|
||||
/// Remove all element in `vec` which `f(element)` returns `false`.
|
||||
///
|
||||
/// TODO: Remove this once the MSRV is bumped to v1.61
|
||||
pub(crate) fn retain_unordered_mut<T, F>(vec: &mut Vec<T>, mut f: F)
|
||||
where
|
||||
F: FnMut(&mut T) -> bool,
|
||||
{
|
||||
let mut i = 0;
|
||||
while i < vec.len() {
|
||||
if f(&mut vec[i]) {
|
||||
i += 1;
|
||||
} else {
|
||||
vec.swap_remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
90
third-party/vendor/cc/src/parallel/stderr.rs
vendored
Normal file
90
third-party/vendor/cc/src/parallel/stderr.rs
vendored
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
/// Helpers functions for [ChildStderr].
|
||||
use std::{convert::TryInto, process::ChildStderr};
|
||||
|
||||
use crate::{Error, ErrorKind};
|
||||
|
||||
#[cfg(all(not(unix), not(windows)))]
|
||||
compile_error!("Only unix and windows support non-blocking pipes! For other OSes, disable the parallel feature.");
|
||||
|
||||
#[cfg(unix)]
|
||||
fn get_flags(fd: std::os::unix::io::RawFd) -> Result<i32, Error> {
|
||||
let flags = unsafe { libc::fcntl(fd, libc::F_GETFL, 0) };
|
||||
if flags == -1 {
|
||||
Err(Error::new(
|
||||
ErrorKind::IOError,
|
||||
format!(
|
||||
"Failed to get flags for pipe {}: {}",
|
||||
fd,
|
||||
std::io::Error::last_os_error()
|
||||
),
|
||||
))
|
||||
} else {
|
||||
Ok(flags)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn set_flags(fd: std::os::unix::io::RawFd, flags: std::os::raw::c_int) -> Result<(), Error> {
|
||||
if unsafe { libc::fcntl(fd, libc::F_SETFL, flags) } == -1 {
|
||||
Err(Error::new(
|
||||
ErrorKind::IOError,
|
||||
format!(
|
||||
"Failed to set flags for pipe {}: {}",
|
||||
fd,
|
||||
std::io::Error::last_os_error()
|
||||
),
|
||||
))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn set_non_blocking(pipe: &impl std::os::unix::io::AsRawFd) -> Result<(), Error> {
|
||||
// On Unix, switch the pipe to non-blocking mode.
|
||||
// On Windows, we have a different way to be non-blocking.
|
||||
let fd = pipe.as_raw_fd();
|
||||
|
||||
let flags = get_flags(fd)?;
|
||||
set_flags(fd, flags | libc::O_NONBLOCK)
|
||||
}
|
||||
|
||||
pub fn bytes_available(stderr: &mut ChildStderr) -> Result<usize, Error> {
|
||||
let mut bytes_available = 0;
|
||||
#[cfg(windows)]
|
||||
{
|
||||
use crate::windows::windows_sys::PeekNamedPipe;
|
||||
use std::os::windows::io::AsRawHandle;
|
||||
use std::ptr::null_mut;
|
||||
if unsafe {
|
||||
PeekNamedPipe(
|
||||
stderr.as_raw_handle(),
|
||||
null_mut(),
|
||||
0,
|
||||
null_mut(),
|
||||
&mut bytes_available,
|
||||
null_mut(),
|
||||
)
|
||||
} == 0
|
||||
{
|
||||
return Err(Error::new(
|
||||
ErrorKind::IOError,
|
||||
format!(
|
||||
"PeekNamedPipe failed with {}",
|
||||
std::io::Error::last_os_error()
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::io::AsRawFd;
|
||||
if unsafe { libc::ioctl(stderr.as_raw_fd(), libc::FIONREAD, &mut bytes_available) } != 0 {
|
||||
return Err(Error::new(
|
||||
ErrorKind::IOError,
|
||||
format!("ioctl failed with {}", std::io::Error::last_os_error()),
|
||||
));
|
||||
}
|
||||
}
|
||||
Ok(bytes_available.try_into().unwrap())
|
||||
}
|
||||
399
third-party/vendor/cc/src/tool.rs
vendored
Normal file
399
third-party/vendor/cc/src/tool.rs
vendored
Normal file
|
|
@ -0,0 +1,399 @@
|
|||
use std::{
|
||||
collections::HashMap,
|
||||
ffi::OsString,
|
||||
path::{Path, PathBuf},
|
||||
process::Command,
|
||||
sync::Mutex,
|
||||
};
|
||||
|
||||
use crate::command_helpers::{run_output, CargoOutput};
|
||||
|
||||
/// Configuration used to represent an invocation of a C compiler.
|
||||
///
|
||||
/// This can be used to figure out what compiler is in use, what the arguments
|
||||
/// to it are, and what the environment variables look like for the compiler.
|
||||
/// This can be used to further configure other build systems (e.g. forward
|
||||
/// along CC and/or CFLAGS) or the `to_command` method can be used to run the
|
||||
/// compiler itself.
|
||||
#[derive(Clone, Debug)]
|
||||
#[allow(missing_docs)]
|
||||
pub struct Tool {
|
||||
pub(crate) path: PathBuf,
|
||||
pub(crate) cc_wrapper_path: Option<PathBuf>,
|
||||
pub(crate) cc_wrapper_args: Vec<OsString>,
|
||||
pub(crate) args: Vec<OsString>,
|
||||
pub(crate) env: Vec<(OsString, OsString)>,
|
||||
pub(crate) family: ToolFamily,
|
||||
pub(crate) cuda: bool,
|
||||
pub(crate) removed_args: Vec<OsString>,
|
||||
pub(crate) has_internal_target_arg: bool,
|
||||
}
|
||||
|
||||
impl Tool {
|
||||
pub(crate) fn new(
|
||||
path: PathBuf,
|
||||
cached_compiler_family: &Mutex<HashMap<Box<Path>, ToolFamily>>,
|
||||
cargo_output: &CargoOutput,
|
||||
) -> Self {
|
||||
Self::with_features(path, None, false, cached_compiler_family, cargo_output)
|
||||
}
|
||||
|
||||
pub(crate) fn with_clang_driver(
|
||||
path: PathBuf,
|
||||
clang_driver: Option<&str>,
|
||||
cached_compiler_family: &Mutex<HashMap<Box<Path>, ToolFamily>>,
|
||||
cargo_output: &CargoOutput,
|
||||
) -> Self {
|
||||
Self::with_features(
|
||||
path,
|
||||
clang_driver,
|
||||
false,
|
||||
cached_compiler_family,
|
||||
cargo_output,
|
||||
)
|
||||
}
|
||||
|
||||
/// Explicitly set the `ToolFamily`, skipping name-based detection.
|
||||
pub(crate) fn with_family(path: PathBuf, family: ToolFamily) -> Self {
|
||||
Self {
|
||||
path,
|
||||
cc_wrapper_path: None,
|
||||
cc_wrapper_args: Vec::new(),
|
||||
args: Vec::new(),
|
||||
env: Vec::new(),
|
||||
family,
|
||||
cuda: false,
|
||||
removed_args: Vec::new(),
|
||||
has_internal_target_arg: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn with_features(
|
||||
path: PathBuf,
|
||||
clang_driver: Option<&str>,
|
||||
cuda: bool,
|
||||
cached_compiler_family: &Mutex<HashMap<Box<Path>, ToolFamily>>,
|
||||
cargo_output: &CargoOutput,
|
||||
) -> Self {
|
||||
fn detect_family_inner(path: &Path, cargo_output: &CargoOutput) -> ToolFamily {
|
||||
let mut cmd = Command::new(path);
|
||||
cmd.arg("--version");
|
||||
|
||||
let stdout = match run_output(
|
||||
&mut cmd,
|
||||
&path.to_string_lossy(),
|
||||
// tool detection issues should always be shown as warnings
|
||||
cargo_output,
|
||||
)
|
||||
.ok()
|
||||
.and_then(|o| String::from_utf8(o).ok())
|
||||
{
|
||||
Some(s) => s,
|
||||
None => {
|
||||
// --version failed. fallback to gnu
|
||||
cargo_output.print_warning(&format_args!("Failed to run: {:?}", cmd));
|
||||
return ToolFamily::Gnu;
|
||||
}
|
||||
};
|
||||
if stdout.contains("clang") {
|
||||
ToolFamily::Clang
|
||||
} else if stdout.contains("GCC") {
|
||||
ToolFamily::Gnu
|
||||
} else {
|
||||
// --version doesn't include clang for GCC
|
||||
cargo_output.print_warning(&format_args!(
|
||||
"Compiler version doesn't include clang or GCC: {:?}",
|
||||
cmd
|
||||
));
|
||||
ToolFamily::Gnu
|
||||
}
|
||||
}
|
||||
let detect_family = |path: &Path| -> ToolFamily {
|
||||
if let Some(family) = cached_compiler_family.lock().unwrap().get(path) {
|
||||
return *family;
|
||||
}
|
||||
|
||||
let family = detect_family_inner(path, cargo_output);
|
||||
cached_compiler_family
|
||||
.lock()
|
||||
.unwrap()
|
||||
.insert(path.into(), family);
|
||||
family
|
||||
};
|
||||
|
||||
// Try to detect family of the tool from its name, falling back to Gnu.
|
||||
let family = if let Some(fname) = path.file_name().and_then(|p| p.to_str()) {
|
||||
if fname.contains("clang-cl") {
|
||||
ToolFamily::Msvc { clang_cl: true }
|
||||
} else if fname.ends_with("cl") || fname == "cl.exe" {
|
||||
ToolFamily::Msvc { clang_cl: false }
|
||||
} else if fname.contains("clang") {
|
||||
match clang_driver {
|
||||
Some("cl") => ToolFamily::Msvc { clang_cl: true },
|
||||
_ => ToolFamily::Clang,
|
||||
}
|
||||
} else {
|
||||
detect_family(&path)
|
||||
}
|
||||
} else {
|
||||
detect_family(&path)
|
||||
};
|
||||
|
||||
Tool {
|
||||
path,
|
||||
cc_wrapper_path: None,
|
||||
cc_wrapper_args: Vec::new(),
|
||||
args: Vec::new(),
|
||||
env: Vec::new(),
|
||||
family,
|
||||
cuda,
|
||||
removed_args: Vec::new(),
|
||||
has_internal_target_arg: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Add an argument to be stripped from the final command arguments.
|
||||
pub(crate) fn remove_arg(&mut self, flag: OsString) {
|
||||
self.removed_args.push(flag);
|
||||
}
|
||||
|
||||
/// Push an "exotic" flag to the end of the compiler's arguments list.
|
||||
///
|
||||
/// Nvidia compiler accepts only the most common compiler flags like `-D`,
|
||||
/// `-I`, `-c`, etc. Options meant specifically for the underlying
|
||||
/// host C++ compiler have to be prefixed with `-Xcompiler`.
|
||||
/// [Another possible future application for this function is passing
|
||||
/// clang-specific flags to clang-cl, which otherwise accepts only
|
||||
/// MSVC-specific options.]
|
||||
pub(crate) fn push_cc_arg(&mut self, flag: OsString) {
|
||||
if self.cuda {
|
||||
self.args.push("-Xcompiler".into());
|
||||
}
|
||||
self.args.push(flag);
|
||||
}
|
||||
|
||||
/// Checks if an argument or flag has already been specified or conflicts.
|
||||
///
|
||||
/// Currently only checks optimization flags.
|
||||
pub(crate) fn is_duplicate_opt_arg(&self, flag: &OsString) -> bool {
|
||||
let flag = flag.to_str().unwrap();
|
||||
let mut chars = flag.chars();
|
||||
|
||||
// Only duplicate check compiler flags
|
||||
if self.is_like_msvc() {
|
||||
if chars.next() != Some('/') {
|
||||
return false;
|
||||
}
|
||||
} else if self.is_like_gnu() || self.is_like_clang() {
|
||||
if chars.next() != Some('-') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for existing optimization flags (-O, /O)
|
||||
if chars.next() == Some('O') {
|
||||
return self
|
||||
.args()
|
||||
.iter()
|
||||
.any(|a| a.to_str().unwrap_or("").chars().nth(1) == Some('O'));
|
||||
}
|
||||
|
||||
// TODO Check for existing -m..., -m...=..., /arch:... flags
|
||||
false
|
||||
}
|
||||
|
||||
/// Don't push optimization arg if it conflicts with existing args.
|
||||
pub(crate) fn push_opt_unless_duplicate(&mut self, flag: OsString) {
|
||||
if self.is_duplicate_opt_arg(&flag) {
|
||||
println!("Info: Ignoring duplicate arg {:?}", &flag);
|
||||
} else {
|
||||
self.push_cc_arg(flag);
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts this compiler into a `Command` that's ready to be run.
|
||||
///
|
||||
/// This is useful for when the compiler needs to be executed and the
|
||||
/// command returned will already have the initial arguments and environment
|
||||
/// variables configured.
|
||||
pub fn to_command(&self) -> Command {
|
||||
let mut cmd = match self.cc_wrapper_path {
|
||||
Some(ref cc_wrapper_path) => {
|
||||
let mut cmd = Command::new(cc_wrapper_path);
|
||||
cmd.arg(&self.path);
|
||||
cmd
|
||||
}
|
||||
None => Command::new(&self.path),
|
||||
};
|
||||
cmd.args(&self.cc_wrapper_args);
|
||||
|
||||
let value = self
|
||||
.args
|
||||
.iter()
|
||||
.filter(|a| !self.removed_args.contains(a))
|
||||
.collect::<Vec<_>>();
|
||||
cmd.args(&value);
|
||||
|
||||
for (k, v) in self.env.iter() {
|
||||
cmd.env(k, v);
|
||||
}
|
||||
cmd
|
||||
}
|
||||
|
||||
/// Returns the path for this compiler.
|
||||
///
|
||||
/// Note that this may not be a path to a file on the filesystem, e.g. "cc",
|
||||
/// but rather something which will be resolved when a process is spawned.
|
||||
pub fn path(&self) -> &Path {
|
||||
&self.path
|
||||
}
|
||||
|
||||
/// Returns the default set of arguments to the compiler needed to produce
|
||||
/// executables for the target this compiler generates.
|
||||
pub fn args(&self) -> &[OsString] {
|
||||
&self.args
|
||||
}
|
||||
|
||||
/// Returns the set of environment variables needed for this compiler to
|
||||
/// operate.
|
||||
///
|
||||
/// This is typically only used for MSVC compilers currently.
|
||||
pub fn env(&self) -> &[(OsString, OsString)] {
|
||||
&self.env
|
||||
}
|
||||
|
||||
/// Returns the compiler command in format of CC environment variable.
|
||||
/// Or empty string if CC env was not present
|
||||
///
|
||||
/// This is typically used by configure script
|
||||
pub fn cc_env(&self) -> OsString {
|
||||
match self.cc_wrapper_path {
|
||||
Some(ref cc_wrapper_path) => {
|
||||
let mut cc_env = cc_wrapper_path.as_os_str().to_owned();
|
||||
cc_env.push(" ");
|
||||
cc_env.push(self.path.to_path_buf().into_os_string());
|
||||
for arg in self.cc_wrapper_args.iter() {
|
||||
cc_env.push(" ");
|
||||
cc_env.push(arg);
|
||||
}
|
||||
cc_env
|
||||
}
|
||||
None => OsString::from(""),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the compiler flags in format of CFLAGS environment variable.
|
||||
/// Important here - this will not be CFLAGS from env, its internal gcc's flags to use as CFLAGS
|
||||
/// This is typically used by configure script
|
||||
pub fn cflags_env(&self) -> OsString {
|
||||
let mut flags = OsString::new();
|
||||
for (i, arg) in self.args.iter().enumerate() {
|
||||
if i > 0 {
|
||||
flags.push(" ");
|
||||
}
|
||||
flags.push(arg);
|
||||
}
|
||||
flags
|
||||
}
|
||||
|
||||
/// Whether the tool is GNU Compiler Collection-like.
|
||||
pub fn is_like_gnu(&self) -> bool {
|
||||
self.family == ToolFamily::Gnu
|
||||
}
|
||||
|
||||
/// Whether the tool is Clang-like.
|
||||
pub fn is_like_clang(&self) -> bool {
|
||||
self.family == ToolFamily::Clang
|
||||
}
|
||||
|
||||
/// Whether the tool is AppleClang under .xctoolchain
|
||||
#[cfg(target_vendor = "apple")]
|
||||
pub(crate) fn is_xctoolchain_clang(&self) -> bool {
|
||||
let path = self.path.to_string_lossy();
|
||||
path.contains(".xctoolchain/")
|
||||
}
|
||||
#[cfg(not(target_vendor = "apple"))]
|
||||
pub(crate) fn is_xctoolchain_clang(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// Whether the tool is MSVC-like.
|
||||
pub fn is_like_msvc(&self) -> bool {
|
||||
match self.family {
|
||||
ToolFamily::Msvc { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the family of tools this tool belongs to.
|
||||
///
|
||||
/// Each family of tools differs in how and what arguments they accept.
|
||||
///
|
||||
/// Detection of a family is done on best-effort basis and may not accurately reflect the tool.
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum ToolFamily {
|
||||
/// Tool is GNU Compiler Collection-like.
|
||||
Gnu,
|
||||
/// Tool is Clang-like. It differs from the GCC in a sense that it accepts superset of flags
|
||||
/// and its cross-compilation approach is different.
|
||||
Clang,
|
||||
/// Tool is the MSVC cl.exe.
|
||||
Msvc { clang_cl: bool },
|
||||
}
|
||||
|
||||
impl ToolFamily {
|
||||
/// What the flag to request debug info for this family of tools look like
|
||||
pub(crate) fn add_debug_flags(&self, cmd: &mut Tool, dwarf_version: Option<u32>) {
|
||||
match *self {
|
||||
ToolFamily::Msvc { .. } => {
|
||||
cmd.push_cc_arg("-Z7".into());
|
||||
}
|
||||
ToolFamily::Gnu | ToolFamily::Clang => {
|
||||
cmd.push_cc_arg(
|
||||
dwarf_version
|
||||
.map_or_else(|| "-g".into(), |v| format!("-gdwarf-{}", v))
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// What the flag to force frame pointers.
|
||||
pub(crate) fn add_force_frame_pointer(&self, cmd: &mut Tool) {
|
||||
match *self {
|
||||
ToolFamily::Gnu | ToolFamily::Clang => {
|
||||
cmd.push_cc_arg("-fno-omit-frame-pointer".into());
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
/// What the flags to enable all warnings
|
||||
pub(crate) fn warnings_flags(&self) -> &'static str {
|
||||
match *self {
|
||||
ToolFamily::Msvc { .. } => "-W4",
|
||||
ToolFamily::Gnu | ToolFamily::Clang => "-Wall",
|
||||
}
|
||||
}
|
||||
|
||||
/// What the flags to enable extra warnings
|
||||
pub(crate) fn extra_warnings_flags(&self) -> Option<&'static str> {
|
||||
match *self {
|
||||
ToolFamily::Msvc { .. } => None,
|
||||
ToolFamily::Gnu | ToolFamily::Clang => Some("-Wextra"),
|
||||
}
|
||||
}
|
||||
|
||||
/// What the flag to turn warning into errors
|
||||
pub(crate) fn warnings_to_errors_flag(&self) -> &'static str {
|
||||
match *self {
|
||||
ToolFamily::Msvc { .. } => "-WX",
|
||||
ToolFamily::Gnu | ToolFamily::Clang => "-Werror",
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn verbose_stderr(&self) -> bool {
|
||||
*self == ToolFamily::Clang
|
||||
}
|
||||
}
|
||||
157
third-party/vendor/cc/src/windows/com.rs
vendored
Normal file
157
third-party/vendor/cc/src/windows/com.rs
vendored
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
// 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::windows::{
|
||||
winapi::{IUnknown, Interface},
|
||||
windows_sys::{
|
||||
CoInitializeEx, SysFreeString, SysStringLen, BSTR, COINIT_MULTITHREADED, HRESULT, S_FALSE,
|
||||
S_OK,
|
||||
},
|
||||
};
|
||||
use std::{
|
||||
convert::TryInto,
|
||||
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.try_into().unwrap()) };
|
||||
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)
|
||||
}
|
||||
}
|
||||
1071
third-party/vendor/cc/src/windows/find_tools.rs
vendored
Normal file
1071
third-party/vendor/cc/src/windows/find_tools.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
20
third-party/vendor/cc/src/windows/mod.rs
vendored
Normal file
20
third-party/vendor/cc/src/windows/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
//! These modules are all glue to support reading the MSVC version from
|
||||
//! the registry and from COM interfaces.
|
||||
|
||||
// This is used in the crate's public API, so don't use #[cfg(windows)]
|
||||
pub mod find_tools;
|
||||
|
||||
#[cfg(windows)]
|
||||
pub(crate) mod windows_sys;
|
||||
|
||||
#[cfg(windows)]
|
||||
mod registry;
|
||||
#[cfg(windows)]
|
||||
#[macro_use]
|
||||
mod winapi;
|
||||
#[cfg(windows)]
|
||||
mod com;
|
||||
#[cfg(windows)]
|
||||
mod setup_config;
|
||||
#[cfg(windows)]
|
||||
mod vs_instances;
|
||||
191
third-party/vendor/cc/src/windows/registry.rs
vendored
Normal file
191
third-party/vendor/cc/src/windows/registry.rs
vendored
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
// 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::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);
|
||||
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
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();
|
||||
}
|
||||
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
third-party/vendor/cc/src/windows/setup_config.rs
vendored
Normal file
283
third-party/vendor/cc/src/windows/setup_config.rs
vendored
Normal 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::windows::{
|
||||
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
third-party/vendor/cc/src/windows/vs_instances.rs
vendored
Normal file
199
third-party/vendor/cc/src/windows/vs_instances.rs
vendored
Normal 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::windows::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
third-party/vendor/cc/src/windows/winapi.rs
vendored
Normal file
146
third-party/vendor/cc/src/windows/winapi.rs
vendored
Normal 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, clippy::upper_case_acronyms)]
|
||||
|
||||
use std::os::raw;
|
||||
|
||||
pub type wchar_t = u16;
|
||||
|
||||
pub use crate::windows::windows_sys::{FILETIME, GUID, HRESULT, SAFEARRAY};
|
||||
|
||||
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::windows::winapi::GUID = $crate::windows::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::windows::winapi::Interface for $interface {
|
||||
#[inline]
|
||||
fn uuidof() -> $crate::windows::winapi::GUID {
|
||||
$crate::windows::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,
|
||||
}}
|
||||
223
third-party/vendor/cc/src/windows/windows_sys.rs
vendored
Normal file
223
third-party/vendor/cc/src/windows/windows_sys.rs
vendored
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
// 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.53.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 FreeLibrary(hlibmodule: HMODULE) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetMachineTypeAttributes(
|
||||
machine: u16,
|
||||
machinetypeattributes: *mut MACHINE_ATTRIBUTES,
|
||||
) -> HRESULT;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetProcAddress(hmodule: HMODULE, lpprocname: PCSTR) -> FARPROC;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn LoadLibraryA(lplibfilename: PCSTR) -> HMODULE;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn OpenSemaphoreA(dwdesiredaccess: u32, binherithandle: BOOL, lpname: PCSTR) -> HANDLE;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn PeekNamedPipe(
|
||||
hnamedpipe: HANDLE,
|
||||
lpbuffer: *mut ::core::ffi::c_void,
|
||||
nbuffersize: u32,
|
||||
lpbytesread: *mut u32,
|
||||
lptotalbytesavail: *mut u32,
|
||||
lpbytesleftthismessage: *mut u32,
|
||||
) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn ReleaseSemaphore(
|
||||
hsemaphore: HANDLE,
|
||||
lreleasecount: i32,
|
||||
lppreviouscount: *mut i32,
|
||||
) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn WaitForSingleObject(hhandle: HANDLE, dwmilliseconds: u32) -> WAIT_EVENT;
|
||||
}
|
||||
#[link(name = "ole32")]
|
||||
extern "system" {
|
||||
pub fn CoCreateInstance(
|
||||
rclsid: *const GUID,
|
||||
punkouter: *mut ::core::ffi::c_void,
|
||||
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: u32) -> 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;
|
||||
pub const FALSE: BOOL = 0i32;
|
||||
pub type FARPROC = ::core::option::Option<unsafe extern "system" fn() -> isize>;
|
||||
#[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 ::core::marker::Copy for GUID {}
|
||||
impl ::core::clone::Clone for GUID {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
pub type HANDLE = *mut ::core::ffi::c_void;
|
||||
pub type HKEY = *mut ::core::ffi::c_void;
|
||||
pub const HKEY_LOCAL_MACHINE: HKEY = -2147483646i32 as _;
|
||||
pub type HMODULE = *mut ::core::ffi::c_void;
|
||||
pub type HRESULT = i32;
|
||||
pub type IMAGE_FILE_MACHINE = u16;
|
||||
pub const IMAGE_FILE_MACHINE_AMD64: IMAGE_FILE_MACHINE = 34404u16;
|
||||
pub const KEY_READ: REG_SAM_FLAGS = 131097u32;
|
||||
pub const KEY_WOW64_32KEY: REG_SAM_FLAGS = 512u32;
|
||||
pub type MACHINE_ATTRIBUTES = i32;
|
||||
pub type PCSTR = *const u8;
|
||||
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
|
||||
}
|
||||
}
|
||||
pub const SEMAPHORE_MODIFY_STATE: SYNCHRONIZATION_ACCESS_RIGHTS = 2u32;
|
||||
pub type SYNCHRONIZATION_ACCESS_RIGHTS = u32;
|
||||
pub const S_FALSE: HRESULT = 0x1_u32 as _;
|
||||
pub const S_OK: HRESULT = 0x0_u32 as _;
|
||||
pub type THREAD_ACCESS_RIGHTS = u32;
|
||||
pub const THREAD_SYNCHRONIZE: THREAD_ACCESS_RIGHTS = 1048576u32;
|
||||
pub const UserEnabled: MACHINE_ATTRIBUTES = 1i32;
|
||||
pub const WAIT_ABANDONED: WAIT_EVENT = 128u32;
|
||||
pub type WAIT_EVENT = u32;
|
||||
pub const WAIT_FAILED: WAIT_EVENT = 4294967295u32;
|
||||
pub const WAIT_OBJECT_0: WAIT_EVENT = 0u32;
|
||||
pub const WAIT_TIMEOUT: WAIT_EVENT = 258u32;
|
||||
pub type WIN32_ERROR = u32;
|
||||
Loading…
Add table
Add a link
Reference in a new issue