Initial vendor packages
Signed-off-by: Valentin Popov <valentin@popov.link>
This commit is contained in:
1
vendor/cc/.cargo-checksum.json
vendored
Normal file
1
vendor/cc/.cargo-checksum.json
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"files":{"Cargo.lock":"f36b5fb99e6a2272cb5ad088fb7e21baa135c5335f9babfd3d6e79cd915d5082","Cargo.toml":"2be00f2836c949a6ff7120610ee0191a6d12d50f141aafd6622d4c2e932f0d71","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"fe18a56553aa54cbef39b659e98340ddf4dbb18f156e7b34a8be25d97e4d123f","src/bin/gcc-shim.rs":"36dc4e447428e73c548cc7106ca1e8f282c098463b014e13a729a44445de4880","src/com.rs":"cf188faf2651f613ee5c38fd6af29188ff4b0c3036b615874bce0e3b6e61a96f","src/lib.rs":"cdf0c6dc4e12ad313fb93ab42f994e26c7e5aaeb07ca61620032d8f4014dacd0","src/os_pipe.rs":"5b950b491b93226885c34a9070387c081f50029fdf19770bb983bca2a64aa705","src/os_pipe/unix.rs":"64a765352b3e94c4590d11f99824dc60a887fe5bc61eba81398aab1180908f55","src/os_pipe/windows.rs":"fa35d5b6adb83a8442ec06b08f3d30631ac7b8513f3cf8b3986d27b7ee58cf93","src/registry.rs":"d888d22abd8a32a61562529274b2d5d2f9e5a3bfa754589d6beb04b740144771","src/setup_config.rs":"5fee84b80d089ae4a92f10080b072ea2bb32c2edbcdc759cb9072e380404fc46","src/vs_instances.rs":"2d3f8278a803b0e7052f4eeb1979b29f963dd0143f4458e2cb5f33c4e5f0963b","src/winapi.rs":"132a7c23d57911db0bef03446cd106e7f75818096132522219d72b9d2a8f247f","src/windows_registry.rs":"c58ae361caf3b6f13dff515e25b3a7e5cf443bb9470d2d347784b5872c3de06d","src/windows_sys.rs":"ff7cdf4450db85c8704dfd3aa765dd62da24f0650825457094405af82958f688","tests/cc_env.rs":"e02b3b0824ad039b47e4462c5ef6dbe6c824c28e7953af94a0f28f7b5158042e","tests/cflags.rs":"57f06eb5ce1557e5b4a032d0c4673e18fbe6f8d26c1deb153126e368b96b41b3","tests/cxxflags.rs":"c2c6c6d8a0d7146616fa1caed26876ee7bc9fcfffd525eb4743593cade5f3371","tests/support/mod.rs":"a3c8d116973bb16066bf6ec4de5143183f97de7aad085d85f8118a2eaac3e1e0","tests/test.rs":"bab74eb7e7a383cb5da4143e74c26ddfa3e7162b5f46c1d46a722250e925444d"},"package":"f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"}
|
111
vendor/cc/Cargo.lock
generated
vendored
Normal file
111
vendor/cc/Cargo.lock
generated
vendored
Normal file
@ -0,0 +1,111 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.83"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
"libc",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499"
|
||||
dependencies = [
|
||||
"instant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.134"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "329c933548736bc49fd575ee68c89e8be4d260064184389a5b77517cddd99ffb"
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"remove_dir_all",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
43
vendor/cc/Cargo.toml
vendored
Normal file
43
vendor/cc/Cargo.toml
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
name = "cc"
|
||||
version = "1.0.83"
|
||||
authors = ["Alex Crichton <alex@alexcrichton.com>"]
|
||||
exclude = ["/.github"]
|
||||
description = """
|
||||
A build-time dependency for Cargo build scripts to assist in invoking the native
|
||||
C compiler to compile native C code into a static archive to be linked into Rust
|
||||
code.
|
||||
"""
|
||||
homepage = "https://github.com/rust-lang/cc-rs"
|
||||
documentation = "https://docs.rs/cc"
|
||||
readme = "README.md"
|
||||
keywords = ["build-dependencies"]
|
||||
categories = ["development-tools::build-utils"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/rust-lang/cc-rs"
|
||||
|
||||
[dependencies.jobserver]
|
||||
version = "0.1.16"
|
||||
optional = true
|
||||
|
||||
[dev-dependencies.tempfile]
|
||||
version = "3"
|
||||
|
||||
[features]
|
||||
parallel = ["jobserver"]
|
||||
|
||||
[target."cfg(unix)".dependencies.libc]
|
||||
version = "0.2.62"
|
||||
default-features = false
|
201
vendor/cc/LICENSE-APACHE
vendored
Normal file
201
vendor/cc/LICENSE-APACHE
vendored
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
25
vendor/cc/LICENSE-MIT
vendored
Normal file
25
vendor/cc/LICENSE-MIT
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
Copyright (c) 2014 Alex Crichton
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
233
vendor/cc/README.md
vendored
Normal file
233
vendor/cc/README.md
vendored
Normal file
@ -0,0 +1,233 @@
|
||||
# cc-rs
|
||||
|
||||
A library to compile C/C++/assembly into a Rust library/application.
|
||||
|
||||
[Documentation](https://docs.rs/cc)
|
||||
|
||||
A simple library meant to be used as a build dependency with Cargo packages in
|
||||
order to build a set of C/C++ files into a static archive. This crate calls out
|
||||
to the most relevant compiler for a platform, for example using `cl` on MSVC.
|
||||
|
||||
## Using cc-rs
|
||||
|
||||
First, you'll want to both add a build script for your crate (`build.rs`) and
|
||||
also add this crate to your `Cargo.toml` via:
|
||||
|
||||
```toml
|
||||
[build-dependencies]
|
||||
cc = "1.0"
|
||||
```
|
||||
|
||||
Next up, you'll want to write a build script like so:
|
||||
|
||||
```rust,no_run
|
||||
// build.rs
|
||||
|
||||
fn main() {
|
||||
cc::Build::new()
|
||||
.file("foo.c")
|
||||
.file("bar.c")
|
||||
.compile("foo");
|
||||
}
|
||||
```
|
||||
|
||||
And that's it! Running `cargo build` should take care of the rest and your Rust
|
||||
application will now have the C files `foo.c` and `bar.c` compiled into a file
|
||||
named `libfoo.a`. If the C files contain
|
||||
|
||||
```c
|
||||
void foo_function(void) { ... }
|
||||
```
|
||||
|
||||
and
|
||||
|
||||
```c
|
||||
int32_t bar_function(int32_t x) { ... }
|
||||
```
|
||||
|
||||
you can call them from Rust by declaring them in
|
||||
your Rust code like so:
|
||||
|
||||
```rust,no_run
|
||||
extern "C" {
|
||||
fn foo_function();
|
||||
fn bar_function(x: i32) -> i32;
|
||||
}
|
||||
|
||||
pub fn call() {
|
||||
unsafe {
|
||||
foo_function();
|
||||
bar_function(42);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
See [the Rustonomicon](https://doc.rust-lang.org/nomicon/ffi.html) for more details.
|
||||
|
||||
## External configuration via environment variables
|
||||
|
||||
To control the programs and flags used for building, the builder can set a
|
||||
number of different environment variables.
|
||||
|
||||
* `CFLAGS` - a series of space separated flags passed to compilers. Note that
|
||||
individual flags cannot currently contain spaces, so doing
|
||||
something like: `-L=foo\ bar` is not possible.
|
||||
* `CC` - the actual C compiler used. Note that this is used as an exact
|
||||
executable name, so (for example) no extra flags can be passed inside
|
||||
this variable, and the builder must ensure that there aren't any
|
||||
trailing spaces. This compiler must understand the `-c` flag. For
|
||||
certain `TARGET`s, it also is assumed to know about other flags (most
|
||||
common is `-fPIC`).
|
||||
* `AR` - the `ar` (archiver) executable to use to build the static library.
|
||||
* `CRATE_CC_NO_DEFAULTS` - the default compiler flags may cause conflicts in
|
||||
some cross compiling scenarios. Setting this variable
|
||||
will disable the generation of default compiler
|
||||
flags.
|
||||
* `CXX...` - see [C++ Support](#c-support).
|
||||
|
||||
Furthermore, projects using this crate may specify custom environment variables
|
||||
to be inspected, for example via the `Build::try_flags_from_environment`
|
||||
function. Consult the project’s own documentation or its use of the `cc` crate
|
||||
for any additional variables it may use.
|
||||
|
||||
Each of these variables can also be supplied with certain prefixes and suffixes,
|
||||
in the following prioritized order:
|
||||
|
||||
1. `<var>_<target>` - for example, `CC_x86_64-unknown-linux-gnu`
|
||||
2. `<var>_<target_with_underscores>` - for example, `CC_x86_64_unknown_linux_gnu`
|
||||
3. `<build-kind>_<var>` - for example, `HOST_CC` or `TARGET_CFLAGS`
|
||||
4. `<var>` - a plain `CC`, `AR` as above.
|
||||
|
||||
If none of these variables exist, cc-rs uses built-in defaults.
|
||||
|
||||
In addition to the above optional environment variables, `cc-rs` has some
|
||||
functions with hard requirements on some variables supplied by [cargo's
|
||||
build-script driver][cargo] that it has the `TARGET`, `OUT_DIR`, `OPT_LEVEL`,
|
||||
and `HOST` variables.
|
||||
|
||||
[cargo]: https://doc.rust-lang.org/cargo/reference/build-scripts.html#inputs-to-the-build-script
|
||||
|
||||
## Optional features
|
||||
|
||||
### Parallel
|
||||
|
||||
Currently cc-rs supports parallel compilation (think `make -jN`) but this
|
||||
feature is turned off by default. To enable cc-rs to compile C/C++ in parallel,
|
||||
you can change your dependency to:
|
||||
|
||||
```toml
|
||||
[build-dependencies]
|
||||
cc = { version = "1.0", features = ["parallel"] }
|
||||
```
|
||||
|
||||
By default cc-rs will limit parallelism to `$NUM_JOBS`, or if not present it
|
||||
will limit it to the number of cpus on the machine. If you are using cargo,
|
||||
use `-jN` option of `build`, `test` and `run` commands as `$NUM_JOBS`
|
||||
is supplied by cargo.
|
||||
|
||||
## Compile-time Requirements
|
||||
|
||||
To work properly this crate needs access to a C compiler when the build script
|
||||
is being run. This crate does not ship a C compiler with it. The compiler
|
||||
required varies per platform, but there are three broad categories:
|
||||
|
||||
* Unix platforms require `cc` to be the C compiler. This can be found by
|
||||
installing cc/clang on Linux distributions and Xcode on macOS, for example.
|
||||
* Windows platforms targeting MSVC (e.g. your target triple ends in `-msvc`)
|
||||
require Visual Studio to be installed. `cc-rs` attempts to locate it, and
|
||||
if it fails, `cl.exe` is expected to be available in `PATH`. This can be
|
||||
set up by running the appropriate developer tools shell.
|
||||
* Windows platforms targeting MinGW (e.g. your target triple ends in `-gnu`)
|
||||
require `cc` to be available in `PATH`. We recommend the
|
||||
[MinGW-w64](https://www.mingw-w64.org/) distribution, which is using the
|
||||
[Win-builds](http://win-builds.org/) installation system.
|
||||
You may also acquire it via
|
||||
[MSYS2](https://www.msys2.org/), as explained [here][msys2-help]. Make sure
|
||||
to install the appropriate architecture corresponding to your installation of
|
||||
rustc. GCC from older [MinGW](http://www.mingw.org/) project is compatible
|
||||
only with 32-bit rust compiler.
|
||||
|
||||
[msys2-help]: https://github.com/rust-lang/rust#building-on-windows
|
||||
|
||||
## C++ support
|
||||
|
||||
`cc-rs` supports C++ libraries compilation by using the `cpp` method on
|
||||
`Build`:
|
||||
|
||||
```rust,no_run
|
||||
fn main() {
|
||||
cc::Build::new()
|
||||
.cpp(true) // Switch to C++ library compilation.
|
||||
.file("foo.cpp")
|
||||
.compile("foo");
|
||||
}
|
||||
```
|
||||
|
||||
For C++ libraries, the `CXX` and `CXXFLAGS` environment variables are used instead of `CC` and `CFLAGS`.
|
||||
|
||||
The C++ standard library may be linked to the crate target. By default it's `libc++` for macOS, FreeBSD, and OpenBSD, `libc++_shared` for Android, nothing for MSVC, and `libstdc++` for anything else. It can be changed in one of two ways:
|
||||
|
||||
1. by using the `cpp_link_stdlib` method on `Build`:
|
||||
```rust,no-run
|
||||
fn main() {
|
||||
cc::Build::new()
|
||||
.cpp(true)
|
||||
.file("foo.cpp")
|
||||
.cpp_link_stdlib("stdc++") // use libstdc++
|
||||
.compile("foo");
|
||||
}
|
||||
```
|
||||
2. by setting the `CXXSTDLIB` environment variable.
|
||||
|
||||
In particular, for Android you may want to [use `c++_static` if you have at most one shared library](https://developer.android.com/ndk/guides/cpp-support).
|
||||
|
||||
Remember that C++ does name mangling so `extern "C"` might be required to enable Rust linker to find your functions.
|
||||
|
||||
## CUDA C++ support
|
||||
|
||||
`cc-rs` also supports compiling CUDA C++ libraries by using the `cuda` method
|
||||
on `Build`:
|
||||
|
||||
```rust,no_run
|
||||
fn main() {
|
||||
cc::Build::new()
|
||||
// Switch to CUDA C++ library compilation using NVCC.
|
||||
.cuda(true)
|
||||
.cudart("static")
|
||||
// Generate code for Maxwell (GTX 970, 980, 980 Ti, Titan X).
|
||||
.flag("-gencode").flag("arch=compute_52,code=sm_52")
|
||||
// Generate code for Maxwell (Jetson TX1).
|
||||
.flag("-gencode").flag("arch=compute_53,code=sm_53")
|
||||
// Generate code for Pascal (GTX 1070, 1080, 1080 Ti, Titan Xp).
|
||||
.flag("-gencode").flag("arch=compute_61,code=sm_61")
|
||||
// Generate code for Pascal (Tesla P100).
|
||||
.flag("-gencode").flag("arch=compute_60,code=sm_60")
|
||||
// Generate code for Pascal (Jetson TX2).
|
||||
.flag("-gencode").flag("arch=compute_62,code=sm_62")
|
||||
// Generate code in parallel
|
||||
.flag("-t0")
|
||||
.file("bar.cu")
|
||||
.compile("bar");
|
||||
}
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under either of
|
||||
|
||||
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
|
||||
https://www.apache.org/licenses/LICENSE-2.0)
|
||||
* MIT license ([LICENSE-MIT](LICENSE-MIT) or
|
||||
https://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
||||
|
||||
### Contribution
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||
for inclusion in cc-rs by you, as defined in the Apache-2.0 license, shall be
|
||||
dual licensed as above, without any additional terms or conditions.
|
70
vendor/cc/src/bin/gcc-shim.rs
vendored
Normal file
70
vendor/cc/src/bin/gcc-shim.rs
vendored
Normal 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
156
vendor/cc/src/com.rs
vendored
Normal 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
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
28
vendor/cc/src/os_pipe.rs
vendored
Normal 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
121
vendor/cc/src/os_pipe/unix.rs
vendored
Normal 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
24
vendor/cc/src/os_pipe/windows.rs
vendored
Normal 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
190
vendor/cc/src/registry.rs
vendored
Normal 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
283
vendor/cc/src/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::{
|
||||
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
199
vendor/cc/src/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::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
146
vendor/cc/src/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)]
|
||||
|
||||
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
896
vendor/cc/src/windows_registry.rs
vendored
Normal 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
198
vendor/cc/src/windows_sys.rs
vendored
Normal 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
|
||||
}
|
118
vendor/cc/tests/cc_env.rs
vendored
Normal file
118
vendor/cc/tests/cc_env.rs
vendored
Normal file
@ -0,0 +1,118 @@
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::path::Path;
|
||||
|
||||
mod support;
|
||||
use crate::support::Test;
|
||||
|
||||
#[test]
|
||||
fn main() {
|
||||
ccache();
|
||||
distcc();
|
||||
ccache_spaces();
|
||||
ccache_env_flags();
|
||||
leading_spaces();
|
||||
extra_flags();
|
||||
path_to_ccache();
|
||||
more_spaces();
|
||||
}
|
||||
|
||||
fn ccache() {
|
||||
let test = Test::gnu();
|
||||
|
||||
env::set_var("CC", "ccache cc");
|
||||
let compiler = test.gcc().file("foo.c").get_compiler();
|
||||
|
||||
assert_eq!(compiler.path(), Path::new("cc"));
|
||||
}
|
||||
|
||||
fn ccache_spaces() {
|
||||
let test = Test::gnu();
|
||||
test.shim("ccache");
|
||||
|
||||
env::set_var("CC", "ccache cc");
|
||||
let compiler = test.gcc().file("foo.c").get_compiler();
|
||||
assert_eq!(compiler.path(), Path::new("cc"));
|
||||
}
|
||||
|
||||
fn distcc() {
|
||||
let test = Test::gnu();
|
||||
test.shim("distcc");
|
||||
|
||||
env::set_var("CC", "distcc cc");
|
||||
let compiler = test.gcc().file("foo.c").get_compiler();
|
||||
assert_eq!(compiler.path(), Path::new("cc"));
|
||||
}
|
||||
|
||||
fn ccache_env_flags() {
|
||||
let test = Test::gnu();
|
||||
test.shim("ccache");
|
||||
|
||||
env::set_var("CC", "ccache lol-this-is-not-a-compiler");
|
||||
let compiler = test.gcc().file("foo.c").get_compiler();
|
||||
assert_eq!(compiler.path(), Path::new("lol-this-is-not-a-compiler"));
|
||||
assert_eq!(
|
||||
compiler.cc_env(),
|
||||
OsString::from("ccache lol-this-is-not-a-compiler")
|
||||
);
|
||||
assert!(
|
||||
compiler
|
||||
.cflags_env()
|
||||
.into_string()
|
||||
.unwrap()
|
||||
.contains("ccache")
|
||||
== false
|
||||
);
|
||||
assert!(
|
||||
compiler
|
||||
.cflags_env()
|
||||
.into_string()
|
||||
.unwrap()
|
||||
.contains(" lol-this-is-not-a-compiler")
|
||||
== false
|
||||
);
|
||||
|
||||
env::set_var("CC", "");
|
||||
}
|
||||
|
||||
fn leading_spaces() {
|
||||
let test = Test::gnu();
|
||||
test.shim("ccache");
|
||||
|
||||
env::set_var("CC", " test ");
|
||||
let compiler = test.gcc().file("foo.c").get_compiler();
|
||||
assert_eq!(compiler.path(), Path::new("test"));
|
||||
|
||||
env::set_var("CC", "");
|
||||
}
|
||||
|
||||
fn extra_flags() {
|
||||
let test = Test::gnu();
|
||||
test.shim("ccache");
|
||||
|
||||
env::set_var("CC", "ccache cc -m32");
|
||||
let compiler = test.gcc().file("foo.c").get_compiler();
|
||||
assert_eq!(compiler.path(), Path::new("cc"));
|
||||
}
|
||||
|
||||
fn path_to_ccache() {
|
||||
let test = Test::gnu();
|
||||
test.shim("ccache");
|
||||
|
||||
env::set_var("CC", "/path/to/ccache.exe cc -m32");
|
||||
let compiler = test.gcc().file("foo.c").get_compiler();
|
||||
assert_eq!(compiler.path(), Path::new("cc"));
|
||||
assert_eq!(
|
||||
compiler.cc_env(),
|
||||
OsString::from("/path/to/ccache.exe cc -m32"),
|
||||
);
|
||||
}
|
||||
|
||||
fn more_spaces() {
|
||||
let test = Test::gnu();
|
||||
test.shim("ccache");
|
||||
|
||||
env::set_var("CC", "cc -m32");
|
||||
let compiler = test.gcc().file("foo.c").get_compiler();
|
||||
assert_eq!(compiler.path(), Path::new("cc"));
|
||||
}
|
15
vendor/cc/tests/cflags.rs
vendored
Normal file
15
vendor/cc/tests/cflags.rs
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
mod support;
|
||||
|
||||
use crate::support::Test;
|
||||
use std::env;
|
||||
|
||||
/// This test is in its own module because it modifies the environment and would affect other tests
|
||||
/// when run in parallel with them.
|
||||
#[test]
|
||||
fn gnu_no_warnings_if_cflags() {
|
||||
env::set_var("CFLAGS", "-arbitrary");
|
||||
let test = Test::gnu();
|
||||
test.gcc().file("foo.c").compile("foo");
|
||||
|
||||
test.cmd(0).must_not_have("-Wall").must_not_have("-Wextra");
|
||||
}
|
15
vendor/cc/tests/cxxflags.rs
vendored
Normal file
15
vendor/cc/tests/cxxflags.rs
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
mod support;
|
||||
|
||||
use crate::support::Test;
|
||||
use std::env;
|
||||
|
||||
/// This test is in its own module because it modifies the environment and would affect other tests
|
||||
/// when run in parallel with them.
|
||||
#[test]
|
||||
fn gnu_no_warnings_if_cxxflags() {
|
||||
env::set_var("CXXFLAGS", "-arbitrary");
|
||||
let test = Test::gnu();
|
||||
test.gcc().file("foo.cpp").cpp(true).compile("foo");
|
||||
|
||||
test.cmd(0).must_not_have("-Wall").must_not_have("-Wextra");
|
||||
}
|
172
vendor/cc/tests/support/mod.rs
vendored
Normal file
172
vendor/cc/tests/support/mod.rs
vendored
Normal file
@ -0,0 +1,172 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::env;
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::fs::{self, File};
|
||||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use cc;
|
||||
use tempfile::{Builder, TempDir};
|
||||
|
||||
pub struct Test {
|
||||
pub td: TempDir,
|
||||
pub gcc: PathBuf,
|
||||
pub msvc: bool,
|
||||
}
|
||||
|
||||
pub struct Execution {
|
||||
args: Vec<String>,
|
||||
}
|
||||
|
||||
impl Test {
|
||||
pub fn new() -> Test {
|
||||
// This is ugly: `sccache` needs to introspect the compiler it is
|
||||
// executing, as it adjusts its behavior depending on the
|
||||
// language/compiler. This crate's test driver uses mock compilers that
|
||||
// are obviously not supported by sccache, so the tests fail if
|
||||
// RUSTC_WRAPPER is set. rust doesn't build test dependencies with
|
||||
// the `test` feature enabled, so we can't conditionally disable the
|
||||
// usage of `sccache` if running in a test environment, at least not
|
||||
// without setting an environment variable here and testing for it
|
||||
// there. Explicitly deasserting RUSTC_WRAPPER here seems to be the
|
||||
// lesser of the two evils.
|
||||
env::remove_var("RUSTC_WRAPPER");
|
||||
|
||||
let mut gcc = PathBuf::from(env::current_exe().unwrap());
|
||||
gcc.pop();
|
||||
if gcc.ends_with("deps") {
|
||||
gcc.pop();
|
||||
}
|
||||
let td = Builder::new().prefix("gcc-test").tempdir_in(&gcc).unwrap();
|
||||
gcc.push(format!("gcc-shim{}", env::consts::EXE_SUFFIX));
|
||||
Test {
|
||||
td: td,
|
||||
gcc: gcc,
|
||||
msvc: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gnu() -> Test {
|
||||
let t = Test::new();
|
||||
t.shim("cc").shim("c++").shim("ar");
|
||||
t
|
||||
}
|
||||
|
||||
pub fn msvc() -> Test {
|
||||
let mut t = Test::new();
|
||||
t.shim("cl").shim("lib.exe");
|
||||
t.msvc = true;
|
||||
t
|
||||
}
|
||||
|
||||
pub fn shim(&self, name: &str) -> &Test {
|
||||
let name = if name.ends_with(env::consts::EXE_SUFFIX) {
|
||||
name.to_string()
|
||||
} else {
|
||||
format!("{}{}", name, env::consts::EXE_SUFFIX)
|
||||
};
|
||||
link_or_copy(&self.gcc, self.td.path().join(name)).unwrap();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn gcc(&self) -> cc::Build {
|
||||
let mut cfg = cc::Build::new();
|
||||
let target = if self.msvc {
|
||||
"x86_64-pc-windows-msvc"
|
||||
} else {
|
||||
"x86_64-unknown-linux-gnu"
|
||||
};
|
||||
|
||||
cfg.target(target)
|
||||
.host(target)
|
||||
.opt_level(2)
|
||||
.debug(false)
|
||||
.out_dir(self.td.path())
|
||||
.__set_env("PATH", self.path())
|
||||
.__set_env("GCCTEST_OUT_DIR", self.td.path());
|
||||
if self.msvc {
|
||||
cfg.compiler(self.td.path().join("cl"));
|
||||
cfg.archiver(self.td.path().join("lib.exe"));
|
||||
}
|
||||
cfg
|
||||
}
|
||||
|
||||
fn path(&self) -> OsString {
|
||||
let mut path = env::split_paths(&env::var_os("PATH").unwrap()).collect::<Vec<_>>();
|
||||
path.insert(0, self.td.path().to_owned());
|
||||
env::join_paths(path).unwrap()
|
||||
}
|
||||
|
||||
pub fn cmd(&self, i: u32) -> Execution {
|
||||
let mut s = String::new();
|
||||
File::open(self.td.path().join(format!("out{}", i)))
|
||||
.unwrap()
|
||||
.read_to_string(&mut s)
|
||||
.unwrap();
|
||||
Execution {
|
||||
args: s.lines().map(|s| s.to_string()).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Execution {
|
||||
pub fn must_have<P: AsRef<OsStr>>(&self, p: P) -> &Execution {
|
||||
if !self.has(p.as_ref()) {
|
||||
panic!("didn't find {:?} in {:?}", p.as_ref(), self.args);
|
||||
} else {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub fn must_not_have<P: AsRef<OsStr>>(&self, p: P) -> &Execution {
|
||||
if self.has(p.as_ref()) {
|
||||
panic!("found {:?}", p.as_ref());
|
||||
} else {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has(&self, p: &OsStr) -> bool {
|
||||
self.args.iter().any(|arg| OsStr::new(arg) == p)
|
||||
}
|
||||
|
||||
pub fn must_have_in_order(&self, before: &str, after: &str) -> &Execution {
|
||||
let before_position = self
|
||||
.args
|
||||
.iter()
|
||||
.rposition(|x| OsStr::new(x) == OsStr::new(before));
|
||||
let after_position = self
|
||||
.args
|
||||
.iter()
|
||||
.rposition(|x| OsStr::new(x) == OsStr::new(after));
|
||||
match (before_position, after_position) {
|
||||
(Some(b), Some(a)) if b < a => {}
|
||||
(b, a) => panic!(
|
||||
"{:?} (last position: {:?}) did not appear before {:?} (last position: {:?})",
|
||||
before, b, after, a
|
||||
),
|
||||
};
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Hard link an executable or copy it if that fails.
|
||||
///
|
||||
/// We first try to hard link an executable to save space. If that fails (as on Windows with
|
||||
/// different mount points, issue #60), we copy.
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
fn link_or_copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
|
||||
let from = from.as_ref();
|
||||
let to = to.as_ref();
|
||||
fs::hard_link(from, to).or_else(|_| fs::copy(from, to).map(|_| ()))
|
||||
}
|
||||
|
||||
/// Copy an executable.
|
||||
///
|
||||
/// On macOS, hard linking the executable leads to strange failures (issue #419), so we just copy.
|
||||
#[cfg(target_os = "macos")]
|
||||
fn link_or_copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
|
||||
fs::copy(from, to).map(|_| ())
|
||||
}
|
477
vendor/cc/tests/test.rs
vendored
Normal file
477
vendor/cc/tests/test.rs
vendored
Normal file
@ -0,0 +1,477 @@
|
||||
use crate::support::Test;
|
||||
|
||||
mod support;
|
||||
|
||||
// Some tests check that a flag is *not* present. These tests might fail if the flag is set in the
|
||||
// CFLAGS or CXXFLAGS environment variables. This function clears the CFLAGS and CXXFLAGS
|
||||
// variables to make sure that the tests can run correctly.
|
||||
fn reset_env() {
|
||||
std::env::set_var("CFLAGS", "");
|
||||
std::env::set_var("CXXFLAGS", "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_smoke() {
|
||||
reset_env();
|
||||
|
||||
let test = Test::gnu();
|
||||
test.gcc().file("foo.c").compile("foo");
|
||||
|
||||
test.cmd(0)
|
||||
.must_have("-O2")
|
||||
.must_have("foo.c")
|
||||
.must_not_have("-gdwarf-4")
|
||||
.must_have("-c")
|
||||
.must_have("-ffunction-sections")
|
||||
.must_have("-fdata-sections");
|
||||
test.cmd(1).must_have(test.td.path().join("foo.o"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_opt_level_1() {
|
||||
reset_env();
|
||||
|
||||
let test = Test::gnu();
|
||||
test.gcc().opt_level(1).file("foo.c").compile("foo");
|
||||
|
||||
test.cmd(0).must_have("-O1").must_not_have("-O2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_opt_level_s() {
|
||||
reset_env();
|
||||
|
||||
let test = Test::gnu();
|
||||
test.gcc().opt_level_str("s").file("foo.c").compile("foo");
|
||||
|
||||
test.cmd(0)
|
||||
.must_have("-Os")
|
||||
.must_not_have("-O1")
|
||||
.must_not_have("-O2")
|
||||
.must_not_have("-O3")
|
||||
.must_not_have("-Oz");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_debug() {
|
||||
let test = Test::gnu();
|
||||
test.gcc().debug(true).file("foo.c").compile("foo");
|
||||
test.cmd(0).must_have("-gdwarf-4");
|
||||
|
||||
let test = Test::gnu();
|
||||
test.gcc()
|
||||
.target("x86_64-apple-darwin")
|
||||
.debug(true)
|
||||
.file("foo.c")
|
||||
.compile("foo");
|
||||
test.cmd(0).must_have("-gdwarf-2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_debug_fp_auto() {
|
||||
let test = Test::gnu();
|
||||
test.gcc().debug(true).file("foo.c").compile("foo");
|
||||
test.cmd(0).must_have("-gdwarf-4");
|
||||
test.cmd(0).must_have("-fno-omit-frame-pointer");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_debug_fp() {
|
||||
let test = Test::gnu();
|
||||
test.gcc().debug(true).file("foo.c").compile("foo");
|
||||
test.cmd(0).must_have("-gdwarf-4");
|
||||
test.cmd(0).must_have("-fno-omit-frame-pointer");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_debug_nofp() {
|
||||
reset_env();
|
||||
|
||||
let test = Test::gnu();
|
||||
test.gcc()
|
||||
.debug(true)
|
||||
.force_frame_pointer(false)
|
||||
.file("foo.c")
|
||||
.compile("foo");
|
||||
test.cmd(0).must_have("-gdwarf-4");
|
||||
test.cmd(0).must_not_have("-fno-omit-frame-pointer");
|
||||
|
||||
let test = Test::gnu();
|
||||
test.gcc()
|
||||
.force_frame_pointer(false)
|
||||
.debug(true)
|
||||
.file("foo.c")
|
||||
.compile("foo");
|
||||
test.cmd(0).must_have("-gdwarf-4");
|
||||
test.cmd(0).must_not_have("-fno-omit-frame-pointer");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_warnings_into_errors() {
|
||||
let test = Test::gnu();
|
||||
test.gcc()
|
||||
.warnings_into_errors(true)
|
||||
.file("foo.c")
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0).must_have("-Werror");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_warnings() {
|
||||
let test = Test::gnu();
|
||||
test.gcc()
|
||||
.warnings(true)
|
||||
.flag("-Wno-missing-field-initializers")
|
||||
.file("foo.c")
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0).must_have("-Wall").must_have("-Wextra");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_extra_warnings0() {
|
||||
reset_env();
|
||||
|
||||
let test = Test::gnu();
|
||||
test.gcc()
|
||||
.warnings(true)
|
||||
.extra_warnings(false)
|
||||
.flag("-Wno-missing-field-initializers")
|
||||
.file("foo.c")
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0).must_have("-Wall").must_not_have("-Wextra");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_extra_warnings1() {
|
||||
reset_env();
|
||||
|
||||
let test = Test::gnu();
|
||||
test.gcc()
|
||||
.warnings(false)
|
||||
.extra_warnings(true)
|
||||
.flag("-Wno-missing-field-initializers")
|
||||
.file("foo.c")
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0).must_not_have("-Wall").must_have("-Wextra");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_warnings_overridable() {
|
||||
reset_env();
|
||||
|
||||
let test = Test::gnu();
|
||||
test.gcc()
|
||||
.warnings(true)
|
||||
.flag("-Wno-missing-field-initializers")
|
||||
.file("foo.c")
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0)
|
||||
.must_have_in_order("-Wall", "-Wno-missing-field-initializers");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_x86_64() {
|
||||
for vendor in &["unknown-linux-gnu", "apple-darwin"] {
|
||||
let target = format!("x86_64-{}", vendor);
|
||||
let test = Test::gnu();
|
||||
test.gcc()
|
||||
.target(&target)
|
||||
.host(&target)
|
||||
.file("foo.c")
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0).must_have("-fPIC").must_have("-m64");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_x86_64_no_pic() {
|
||||
reset_env();
|
||||
|
||||
for vendor in &["unknown-linux-gnu", "apple-darwin"] {
|
||||
let target = format!("x86_64-{}", vendor);
|
||||
let test = Test::gnu();
|
||||
test.gcc()
|
||||
.pic(false)
|
||||
.target(&target)
|
||||
.host(&target)
|
||||
.file("foo.c")
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0).must_not_have("-fPIC");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_i686() {
|
||||
for vendor in &["unknown-linux-gnu", "apple-darwin"] {
|
||||
let target = format!("i686-{}", vendor);
|
||||
let test = Test::gnu();
|
||||
test.gcc()
|
||||
.target(&target)
|
||||
.host(&target)
|
||||
.file("foo.c")
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0).must_have("-m32");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_i686_pic() {
|
||||
for vendor in &["unknown-linux-gnu", "apple-darwin"] {
|
||||
let target = format!("i686-{}", vendor);
|
||||
let test = Test::gnu();
|
||||
test.gcc()
|
||||
.pic(true)
|
||||
.target(&target)
|
||||
.host(&target)
|
||||
.file("foo.c")
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0).must_have("-fPIC");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_x86_64_no_plt() {
|
||||
let target = "x86_64-unknown-linux-gnu";
|
||||
let test = Test::gnu();
|
||||
test.gcc()
|
||||
.pic(true)
|
||||
.use_plt(false)
|
||||
.target(&target)
|
||||
.host(&target)
|
||||
.file("foo.c")
|
||||
.compile("foo");
|
||||
test.cmd(0).must_have("-fno-plt");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_set_stdlib() {
|
||||
reset_env();
|
||||
|
||||
let test = Test::gnu();
|
||||
test.gcc()
|
||||
.cpp_set_stdlib(Some("foo"))
|
||||
.file("foo.c")
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0).must_not_have("-stdlib=foo");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_include() {
|
||||
let test = Test::gnu();
|
||||
test.gcc().include("foo/bar").file("foo.c").compile("foo");
|
||||
|
||||
test.cmd(0).must_have("-I").must_have("foo/bar");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_define() {
|
||||
let test = Test::gnu();
|
||||
test.gcc()
|
||||
.define("FOO", "bar")
|
||||
.define("BAR", None)
|
||||
.file("foo.c")
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0).must_have("-DFOO=bar").must_have("-DBAR");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_compile_assembly() {
|
||||
let test = Test::gnu();
|
||||
test.gcc().file("foo.S").compile("foo");
|
||||
test.cmd(0).must_have("foo.S");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_shared() {
|
||||
reset_env();
|
||||
|
||||
let test = Test::gnu();
|
||||
test.gcc()
|
||||
.file("foo.c")
|
||||
.shared_flag(true)
|
||||
.static_flag(false)
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0).must_have("-shared").must_not_have("-static");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_flag_if_supported() {
|
||||
reset_env();
|
||||
|
||||
if cfg!(windows) {
|
||||
return;
|
||||
}
|
||||
let test = Test::gnu();
|
||||
test.gcc()
|
||||
.file("foo.c")
|
||||
.flag("-v")
|
||||
.flag_if_supported("-Wall")
|
||||
.flag_if_supported("-Wflag-does-not-exist")
|
||||
.flag_if_supported("-std=c++11")
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0)
|
||||
.must_have("-v")
|
||||
.must_have("-Wall")
|
||||
.must_not_have("-Wflag-does-not-exist")
|
||||
.must_not_have("-std=c++11");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_flag_if_supported_cpp() {
|
||||
if cfg!(windows) {
|
||||
return;
|
||||
}
|
||||
let test = Test::gnu();
|
||||
test.gcc()
|
||||
.cpp(true)
|
||||
.file("foo.cpp")
|
||||
.flag_if_supported("-std=c++11")
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0).must_have("-std=c++11");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_static() {
|
||||
reset_env();
|
||||
|
||||
let test = Test::gnu();
|
||||
test.gcc()
|
||||
.file("foo.c")
|
||||
.shared_flag(false)
|
||||
.static_flag(true)
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0).must_have("-static").must_not_have("-shared");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_no_dash_dash() {
|
||||
let test = Test::gnu();
|
||||
test.gcc().file("foo.c").compile("foo");
|
||||
|
||||
test.cmd(0).must_not_have("--");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_std_c() {
|
||||
let test = Test::gnu();
|
||||
test.gcc().file("foo.c").std("c11").compile("foo");
|
||||
|
||||
test.cmd(0).must_have("-std=c11");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn msvc_smoke() {
|
||||
reset_env();
|
||||
|
||||
let test = Test::msvc();
|
||||
test.gcc().file("foo.c").compile("foo");
|
||||
|
||||
test.cmd(0)
|
||||
.must_have("-O2")
|
||||
.must_have("foo.c")
|
||||
.must_not_have("-Z7")
|
||||
.must_have("-c")
|
||||
.must_have("-MD");
|
||||
test.cmd(1).must_have(test.td.path().join("foo.o"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn msvc_opt_level_0() {
|
||||
reset_env();
|
||||
|
||||
let test = Test::msvc();
|
||||
test.gcc().opt_level(0).file("foo.c").compile("foo");
|
||||
|
||||
test.cmd(0).must_not_have("-O2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn msvc_debug() {
|
||||
let test = Test::msvc();
|
||||
test.gcc().debug(true).file("foo.c").compile("foo");
|
||||
test.cmd(0).must_have("-Z7");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn msvc_include() {
|
||||
let test = Test::msvc();
|
||||
test.gcc().include("foo/bar").file("foo.c").compile("foo");
|
||||
|
||||
test.cmd(0).must_have("-I").must_have("foo/bar");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn msvc_define() {
|
||||
let test = Test::msvc();
|
||||
test.gcc()
|
||||
.define("FOO", "bar")
|
||||
.define("BAR", None)
|
||||
.file("foo.c")
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0).must_have("-DFOO=bar").must_have("-DBAR");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn msvc_static_crt() {
|
||||
let test = Test::msvc();
|
||||
test.gcc().static_crt(true).file("foo.c").compile("foo");
|
||||
|
||||
test.cmd(0).must_have("-MT");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn msvc_no_static_crt() {
|
||||
let test = Test::msvc();
|
||||
test.gcc().static_crt(false).file("foo.c").compile("foo");
|
||||
|
||||
test.cmd(0).must_have("-MD");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn msvc_no_dash_dash() {
|
||||
let test = Test::msvc();
|
||||
test.gcc().file("foo.c").compile("foo");
|
||||
|
||||
test.cmd(0).must_not_have("--");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn msvc_std_c() {
|
||||
let test = Test::msvc();
|
||||
test.gcc().file("foo.c").std("c11").compile("foo");
|
||||
|
||||
test.cmd(0).must_have("-std:c11");
|
||||
}
|
||||
|
||||
// Disable this test with the parallel feature because the execution
|
||||
// order is not deterministic.
|
||||
#[cfg(not(feature = "parallel"))]
|
||||
#[test]
|
||||
fn asm_flags() {
|
||||
let test = Test::gnu();
|
||||
test.gcc()
|
||||
.file("foo.c")
|
||||
.file("x86_64.asm")
|
||||
.file("x86_64.S")
|
||||
.asm_flag("--abc")
|
||||
.compile("foo");
|
||||
test.cmd(0).must_not_have("--abc");
|
||||
test.cmd(1).must_have("--abc");
|
||||
test.cmd(2).must_have("--abc");
|
||||
}
|
Reference in New Issue
Block a user