mirror of
https://github.com/openharmony/third_party_rust_autocfg.git
synced 2026-07-01 22:34:02 -04:00
merge master into master
autocfg 升级到1.4.0 Created-by: dragonswordy Commit-by: ljy9810 Merged-by: openharmony_ci Description: ### 一、内容说明(相关的Issue) https://gitcode.com/openharmony/third_party_rust_memoffset/issues/1 ### 二、建议测试周期和提测地址 建议测试完成时间:xxxx.xx.xx 投产上线时间:xxxx.xx.xx 提测地址:CI环境/压测环境 测试账号: ### 三、变更内容 * 3.1 关联PR列表 * 3.2 数据库和部署说明 1. 常规更新 2. 重启unicorn 3. 重启sidekiq 4. 迁移任务:是否有迁移任务,没有写 "无" 5. rake脚本:`bundle exec xxx RAILS_ENV = production`;没有写 "无" * 3.4 其他技术优化内容(做了什么,变更了什么) - 重构了 xxxx 代码 - xxxx 算法优化 * 3.5 废弃通知(什么字段、方法弃用?) * 3.6 后向不兼容变更(是否有无法向后兼容的变更?) ### 四、研发自测点(自测哪些?冒烟用例全部自测?) 自测测试结论: ### 五、测试关注点(需要提醒QA重点关注的、可能会忽略的地方) 检查点: | 需求名称 | 是否影响xx公共模块 | 是否需要xx功能 | 需求升级是否依赖其他子产品 | |------|------------|----------|---------------| | xxx | 否 | 需要 | 不需要 | | | | | | 接口测试: 性能测试: 并发测试: 其他: See merge request: openharmony/third_party_rust_autocfg!3
This commit is contained in:
+35
-56
@@ -1,9 +1,9 @@
|
||||
name: CI
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- staging
|
||||
- trying
|
||||
- master
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -13,85 +13,64 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
rust: [1.0.0, 1.5.0, 1.10.0, 1.15.0, 1.20.0, 1.25.0, 1.30.0, 1.35.0,
|
||||
1.40.0, 1.45.0, 1.50.0, 1.55.0, stable, beta, nightly]
|
||||
1.40.0, 1.45.0, 1.50.0, 1.55.0, 1.60.0, 1.65.0, 1.70.0, 1.75.0,
|
||||
1.80.0, # first version with rustc-check-cfg
|
||||
stable, beta, nightly]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Install
|
||||
uses: actions-rs/toolchain@v1
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
profile: minimal
|
||||
override: true
|
||||
- name: Build
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --verbose
|
||||
- name: Test
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --verbose
|
||||
- run: cargo build --verbose
|
||||
- run: cargo test --verbose
|
||||
- run: cargo run
|
||||
working-directory: ./ci/verify-check-cfg
|
||||
|
||||
# try probing a target that doesn't have std at all
|
||||
no_std:
|
||||
name: No Std
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
- name: Install
|
||||
uses: actions-rs/toolchain@v1
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
toolchain: stable
|
||||
target: thumbv6m-none-eabi
|
||||
profile: minimal
|
||||
override: true
|
||||
- name: Test
|
||||
- run: cargo test --verbose --lib
|
||||
env:
|
||||
TARGET: thumbv6m-none-eabi
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --verbose --lib
|
||||
|
||||
# we don't even need an installed target for version checks
|
||||
missing_target:
|
||||
name: Missing Target
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
- name: Install
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
profile: minimal
|
||||
override: true
|
||||
- name: Test
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- run: cargo test --verbose --lib -- version
|
||||
env:
|
||||
TARGET: thumbv6m-none-eabi
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --verbose --lib -- version
|
||||
|
||||
fmt:
|
||||
name: Format
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Install
|
||||
uses: actions-rs/toolchain@v1
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@1.77.0
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: 1.58.1
|
||||
override: true
|
||||
components: rustfmt
|
||||
- name: Check formatting
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fmt
|
||||
args: --all -- --check
|
||||
- run: cargo fmt --all --check
|
||||
|
||||
# One job that "summarizes" the success state of this pipeline. This can then be added to branch
|
||||
# protection, rather than having to add each job separately.
|
||||
success:
|
||||
name: Success
|
||||
runs-on: ubuntu-latest
|
||||
needs: [test, no_std, missing_target, fmt]
|
||||
# Github branch protection is exceedingly silly and treats "jobs skipped because a dependency
|
||||
# failed" as success. So we have to do some contortions to ensure the job fails if any of its
|
||||
# dependencies fails.
|
||||
if: always() # make sure this is never "skipped"
|
||||
steps:
|
||||
# Manually check the status of all dependencies. `if: failure()` does not work.
|
||||
- name: check if any dependency failed
|
||||
run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}'
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
name: master
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
schedule:
|
||||
- cron: '0 0 * * 0' # 00:00 Sunday
|
||||
|
||||
jobs:
|
||||
|
||||
test:
|
||||
name: Test
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
rust: [1.0.0, stable]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Install
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
profile: minimal
|
||||
override: true
|
||||
- name: Build
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --verbose
|
||||
- name: Test
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --verbose
|
||||
@@ -1,50 +0,0 @@
|
||||
name: PR
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
|
||||
test:
|
||||
name: Test
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
rust: [1.0.0, stable]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Install
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
profile: minimal
|
||||
override: true
|
||||
- name: Build
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --verbose
|
||||
- name: Test
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --verbose
|
||||
|
||||
fmt:
|
||||
name: Format
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Install
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: 1.58.1
|
||||
override: true
|
||||
components: rustfmt
|
||||
- name: Check formatting
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fmt
|
||||
args: --all -- --check
|
||||
+4
-2
@@ -1,13 +1,15 @@
|
||||
[package]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
version = "1.4.0"
|
||||
authors = ["Josh Stone <cuviper@gmail.com>"]
|
||||
license = "Apache-2.0 OR MIT"
|
||||
repository = "https://github.com/cuviper/autocfg"
|
||||
documentation = "https://docs.rs/autocfg/"
|
||||
description = "Automatic cfg for Rust compiler features"
|
||||
readme = "README.md"
|
||||
keywords = ["rustc", "build", "autoconf"]
|
||||
categories = ["development-tools::build-utils"]
|
||||
exclude = ["/.github/**", "/bors.toml"]
|
||||
exclude = ["/.github/**"]
|
||||
rust-version = "1.0"
|
||||
|
||||
[dependencies]
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
"Name": "autocfg",
|
||||
"License": "Apache License V2.0, MIT",
|
||||
"License File": "LICENSE-APACHE, LICENSE-MIT",
|
||||
"Version Number": "1.1.0",
|
||||
"Version Number": "1.4.0",
|
||||
"Owner": "fangting12@huawei.com",
|
||||
"Upstream URL": "https://github.com/cuviper/autocfg",
|
||||
"Description": "A library that generates Rust code based on compile-time configuration options."
|
||||
|
||||
@@ -43,6 +43,23 @@ should only be used when the compiler supports it.
|
||||
|
||||
## Release Notes
|
||||
|
||||
- 1.4.0 (2024-09-26)
|
||||
|
||||
- Add `emit_possibility` for Rust 1.80's [checked cfgs], and call that
|
||||
automatically for methods that conditionally `emit`, by @Techcable.
|
||||
|
||||
[checked cfgs]: https://blog.rust-lang.org/2024/05/06/check-cfg.html
|
||||
|
||||
- 1.3.0 (2024-05-03)
|
||||
|
||||
- Add `probe_raw` for direct control of the code that will be test-compiled.
|
||||
- Use wrappers when querying the `rustc` version information too.
|
||||
|
||||
- 1.2.0 (2024-03-25)
|
||||
|
||||
- Add `no_std` and `set_no_std` to control the use of `#![no_std]` in probes.
|
||||
- Use `RUSTC_WRAPPER` and `RUSTC_WORKSPACE_WRAPPER` when they are set.
|
||||
|
||||
- 1.1.0 (2022-02-07)
|
||||
- Use `CARGO_ENCODED_RUSTFLAGS` when it is set.
|
||||
|
||||
@@ -88,8 +105,8 @@ treated as a major breaking change for semver purposes.
|
||||
This project is licensed under either of
|
||||
|
||||
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
|
||||
http://www.apache.org/licenses/LICENSE-2.0)
|
||||
https://www.apache.org/licenses/LICENSE-2.0)
|
||||
* MIT license ([LICENSE-MIT](LICENSE-MIT) or
|
||||
http://opensource.org/licenses/MIT)
|
||||
https://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
status = [
|
||||
"Test (1.0.0)",
|
||||
"Test (1.5.0)",
|
||||
"Test (1.10.0)",
|
||||
"Test (1.15.0)",
|
||||
"Test (1.20.0)",
|
||||
"Test (1.25.0)",
|
||||
"Test (1.30.0)",
|
||||
"Test (1.35.0)",
|
||||
"Test (1.40.0)",
|
||||
"Test (1.45.0)",
|
||||
"Test (1.50.0)",
|
||||
"Test (1.55.0)",
|
||||
"Test (stable)",
|
||||
"Test (beta)",
|
||||
"Test (nightly)",
|
||||
"No Std",
|
||||
"Missing Target",
|
||||
"Format",
|
||||
]
|
||||
@@ -0,0 +1,3 @@
|
||||
# Rust
|
||||
/target
|
||||
/Cargo.lock
|
||||
@@ -0,0 +1,14 @@
|
||||
[package]
|
||||
# NOTE: Cannot be in workspace because of rustc 1.0 support
|
||||
name = "autocfg-verify-check-cfg"
|
||||
description = "A dummy crate to verify autocfg is emitting check-cfg directives"
|
||||
version = "0.1.0"
|
||||
edition = "2015"
|
||||
# only for testing
|
||||
publish = false
|
||||
|
||||
build = "build.rs"
|
||||
|
||||
[build-dependencies]
|
||||
autocfg = { path = "../.." }
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
extern crate autocfg;
|
||||
|
||||
pub fn main() {
|
||||
let cfg = autocfg::AutoCfg::new().unwrap();
|
||||
|
||||
//
|
||||
// tests
|
||||
//
|
||||
|
||||
// always true
|
||||
cfg.emit_rustc_version(1, 0);
|
||||
// should always be false
|
||||
cfg.emit_rustc_version(7, std::u32::MAX as usize);
|
||||
|
||||
// always true
|
||||
cfg.emit_has_path("std::vec::Vec");
|
||||
cfg.emit_path_cfg("std::vec::Vec", "has_path_std_vec");
|
||||
// always false
|
||||
cfg.emit_has_path("dummy::DummyPath");
|
||||
cfg.emit_path_cfg("dummy::DummyPath", "has_path_dummy");
|
||||
|
||||
// always true
|
||||
cfg.emit_has_trait("std::ops::Add");
|
||||
cfg.emit_trait_cfg("std::ops::Add", "has_trait_add");
|
||||
// always false
|
||||
cfg.emit_has_trait("dummy::DummyTrait");
|
||||
cfg.emit_trait_cfg("dummy::DummyTrait", "has_trait_dummy");
|
||||
|
||||
// always true
|
||||
cfg.emit_has_type("i32");
|
||||
cfg.emit_type_cfg("i32", "has_type_i32");
|
||||
// always false
|
||||
cfg.emit_has_type("i7billion");
|
||||
cfg.emit_type_cfg("i7billion", "has_type_i7billion");
|
||||
|
||||
// always true
|
||||
cfg.emit_expression_cfg("3 + 7", "has_working_addition");
|
||||
// always false
|
||||
cfg.emit_expression_cfg("3 ^^^^^ 12", "has_working_5xor");
|
||||
|
||||
// always true
|
||||
cfg.emit_constant_cfg("7", "has_const_7");
|
||||
// false - Opening file should never be `const`
|
||||
cfg.emit_constant_cfg("std::fs::File::open(\"foo.txt\")", "has_const_file_open");
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#![allow(unknown_lints)]
|
||||
#![deny(unexpected_cfgs)]
|
||||
|
||||
macro_rules! test_cfgs {
|
||||
($($cfg:ident,)*) => {$({
|
||||
let cfg_desc = format!("cfg!({})", stringify!($cfg));
|
||||
if cfg!($cfg) {
|
||||
println!("Enabled: {}", cfg_desc);
|
||||
} else {
|
||||
println!("Disabled: {}", cfg_desc);
|
||||
}
|
||||
})*};
|
||||
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
test_cfgs!(
|
||||
// emit_rustc_version
|
||||
rustc_1_0,
|
||||
rustc_7_4294967295,
|
||||
// emit_has_path, emit_path_cfg
|
||||
has_std__vec__Vec,
|
||||
has_path_std_vec,
|
||||
has_dummy__DummyPath,
|
||||
has_path_dummy,
|
||||
// emit_has_trait, emit_trait_cfg
|
||||
has_std__ops__Add,
|
||||
has_trait_add,
|
||||
has_dummy__DummyTrait,
|
||||
has_trait_dummy,
|
||||
// emit_has_type, has_type_i32
|
||||
has_i32,
|
||||
has_type_i32,
|
||||
has_i7billion,
|
||||
has_type_i7billion,
|
||||
// emit_expression_cfg
|
||||
has_working_addition,
|
||||
has_working_5xor,
|
||||
// emit_constant_cfg
|
||||
has_const_7,
|
||||
has_const_file_open,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
extern crate autocfg;
|
||||
|
||||
fn main() {
|
||||
// Normally, cargo will set `OUT_DIR` for build scripts.
|
||||
let ac = autocfg::AutoCfg::with_dir("target").unwrap();
|
||||
|
||||
// When this feature was stabilized, it also renamed the method to
|
||||
// `chunk_by`, so it's important to *use* the feature in your probe.
|
||||
let code = r#"
|
||||
#![feature(slice_group_by)]
|
||||
pub fn probe(slice: &[i32]) -> impl Iterator<Item = &[i32]> {
|
||||
slice.group_by(|a, b| a == b)
|
||||
}
|
||||
"#;
|
||||
if ac.probe_raw(code).is_ok() {
|
||||
autocfg::emit("has_slice_group_by");
|
||||
}
|
||||
}
|
||||
+13
-1
@@ -2,6 +2,7 @@ use std::error;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use std::num;
|
||||
use std::process;
|
||||
use std::str;
|
||||
|
||||
/// A common error type for the `autocfg` crate.
|
||||
@@ -20,7 +21,7 @@ impl error::Error for Error {
|
||||
ErrorKind::Io(ref e) => Some(e),
|
||||
ErrorKind::Num(ref e) => Some(e),
|
||||
ErrorKind::Utf8(ref e) => Some(e),
|
||||
ErrorKind::Other(_) => None,
|
||||
ErrorKind::Process(_) | ErrorKind::Other(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,6 +32,10 @@ impl fmt::Display for Error {
|
||||
ErrorKind::Io(ref e) => e.fmt(f),
|
||||
ErrorKind::Num(ref e) => e.fmt(f),
|
||||
ErrorKind::Utf8(ref e) => e.fmt(f),
|
||||
ErrorKind::Process(ref status) => {
|
||||
// Same message as the newer `ExitStatusError`
|
||||
write!(f, "process exited unsuccessfully: {}", status)
|
||||
}
|
||||
ErrorKind::Other(s) => s.fmt(f),
|
||||
}
|
||||
}
|
||||
@@ -40,10 +45,17 @@ impl fmt::Display for Error {
|
||||
enum ErrorKind {
|
||||
Io(io::Error),
|
||||
Num(num::ParseIntError),
|
||||
Process(process::ExitStatus),
|
||||
Utf8(str::Utf8Error),
|
||||
Other(&'static str),
|
||||
}
|
||||
|
||||
pub fn from_exit(status: process::ExitStatus) -> Error {
|
||||
Error {
|
||||
kind: ErrorKind::Process(status),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_io(e: io::Error) -> Error {
|
||||
Error {
|
||||
kind: ErrorKind::Io(e),
|
||||
|
||||
+183
-46
@@ -20,7 +20,8 @@
|
||||
//!
|
||||
//! fn main() {
|
||||
//! # // Normally, cargo will set `OUT_DIR` for build scripts.
|
||||
//! # std::env::set_var("OUT_DIR", "target");
|
||||
//! # let exe = std::env::current_exe().unwrap();
|
||||
//! # std::env::set_var("OUT_DIR", exe.parent().unwrap());
|
||||
//! let ac = autocfg::new();
|
||||
//! ac.emit_has_type("i128");
|
||||
//!
|
||||
@@ -61,10 +62,11 @@ macro_rules! try {
|
||||
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::fmt::Arguments;
|
||||
use std::fs;
|
||||
use std::io::{stderr, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{Command, Stdio};
|
||||
use std::process::Stdio;
|
||||
#[allow(deprecated)]
|
||||
use std::sync::atomic::ATOMIC_USIZE_INIT;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
@@ -72,6 +74,9 @@ use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
mod error;
|
||||
pub use error::Error;
|
||||
|
||||
mod rustc;
|
||||
use rustc::Rustc;
|
||||
|
||||
mod version;
|
||||
use version::Version;
|
||||
|
||||
@@ -82,11 +87,12 @@ mod tests;
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct AutoCfg {
|
||||
out_dir: PathBuf,
|
||||
rustc: PathBuf,
|
||||
rustc: Rustc,
|
||||
rustc_version: Version,
|
||||
target: Option<OsString>,
|
||||
no_std: bool,
|
||||
rustflags: Vec<String>,
|
||||
uuid: u64,
|
||||
}
|
||||
|
||||
/// Writes a config flag for rustc on standard out.
|
||||
@@ -94,6 +100,12 @@ pub struct AutoCfg {
|
||||
/// This looks like: `cargo:rustc-cfg=CFG`
|
||||
///
|
||||
/// Cargo will use this in arguments to rustc, like `--cfg CFG`.
|
||||
///
|
||||
/// This does not automatically call [`emit_possibility`]
|
||||
/// so the compiler my generate an [`unexpected_cfgs` warning][check-cfg-flags].
|
||||
/// However, all the builtin emit methods on [`AutoCfg`] call [`emit_possibility`] automatically.
|
||||
///
|
||||
/// [check-cfg-flags]: https://blog.rust-lang.org/2024/05/06/check-cfg.html
|
||||
pub fn emit(cfg: &str) {
|
||||
println!("cargo:rustc-cfg={}", cfg);
|
||||
}
|
||||
@@ -119,7 +131,26 @@ pub fn rerun_env(var: &str) {
|
||||
println!("cargo:rerun-if-env-changed={}", var);
|
||||
}
|
||||
|
||||
/// Create a new `AutoCfg` instance.
|
||||
/// Indicates to rustc that a config flag should not generate an [`unexpected_cfgs` warning][check-cfg-flags]
|
||||
///
|
||||
/// This looks like `cargo:rustc-check-cfg=cfg(VAR)`
|
||||
///
|
||||
/// As of rust 1.80, the compiler does [automatic checking of cfgs at compile time][check-cfg-flags].
|
||||
/// All custom configuration flags must be known to rustc, or they will generate a warning.
|
||||
/// This is done automatically when calling the builtin emit methods on [`AutoCfg`],
|
||||
/// but not when calling [`autocfg::emit`](crate::emit) directly.
|
||||
///
|
||||
/// Versions before rust 1.80 will simply ignore this directive.
|
||||
///
|
||||
/// This function indicates to the compiler that the config flag never has a value.
|
||||
/// If this is not desired, see [the blog post][check-cfg].
|
||||
///
|
||||
/// [check-cfg-flags]: https://blog.rust-lang.org/2024/05/06/check-cfg.html
|
||||
pub fn emit_possibility(cfg: &str) {
|
||||
println!("cargo:rustc-check-cfg=cfg({})", cfg);
|
||||
}
|
||||
|
||||
/// Creates a new `AutoCfg` instance.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
@@ -129,7 +160,7 @@ pub fn new() -> AutoCfg {
|
||||
}
|
||||
|
||||
impl AutoCfg {
|
||||
/// Create a new `AutoCfg` instance.
|
||||
/// Creates a new `AutoCfg` instance.
|
||||
///
|
||||
/// # Common errors
|
||||
///
|
||||
@@ -144,7 +175,7 @@ impl AutoCfg {
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new `AutoCfg` instance with the specified output directory.
|
||||
/// Creates a new `AutoCfg` instance with the specified output directory.
|
||||
///
|
||||
/// # Common errors
|
||||
///
|
||||
@@ -153,9 +184,8 @@ impl AutoCfg {
|
||||
/// - `dir` is not a writable directory.
|
||||
///
|
||||
pub fn with_dir<T: Into<PathBuf>>(dir: T) -> Result<Self, Error> {
|
||||
let rustc = env::var_os("RUSTC").unwrap_or_else(|| "rustc".into());
|
||||
let rustc: PathBuf = rustc.into();
|
||||
let rustc_version = try!(Version::from_rustc(&rustc));
|
||||
let rustc = Rustc::new();
|
||||
let rustc_version = try!(rustc.version());
|
||||
|
||||
let target = env::var_os("TARGET");
|
||||
|
||||
@@ -173,14 +203,15 @@ impl AutoCfg {
|
||||
rustc_version: rustc_version,
|
||||
target: target,
|
||||
no_std: false,
|
||||
uuid: new_uuid(),
|
||||
};
|
||||
|
||||
// Sanity check with and without `std`.
|
||||
if !ac.probe("").unwrap_or(false) {
|
||||
ac.no_std = true;
|
||||
if !ac.probe("").unwrap_or(false) {
|
||||
if !ac.probe_raw("").is_ok() {
|
||||
if ac.probe_raw("#![no_std]").is_ok() {
|
||||
ac.no_std = true;
|
||||
} else {
|
||||
// Neither worked, so assume nothing...
|
||||
ac.no_std = false;
|
||||
let warning = b"warning: autocfg could not probe for `std`\n";
|
||||
stderr().write_all(warning).ok();
|
||||
}
|
||||
@@ -188,7 +219,34 @@ impl AutoCfg {
|
||||
Ok(ac)
|
||||
}
|
||||
|
||||
/// Test whether the current `rustc` reports a version greater than
|
||||
/// Returns whether `AutoCfg` is using `#![no_std]` in its probes.
|
||||
///
|
||||
/// This is automatically detected during construction -- if an empty probe
|
||||
/// fails while one with `#![no_std]` succeeds, then the attribute will be
|
||||
/// used for all further probes. This is usually only necessary when the
|
||||
/// `TARGET` lacks `std` altogether. If neither succeeds, `no_std` is not
|
||||
/// set, but that `AutoCfg` will probably only work for version checks.
|
||||
///
|
||||
/// This attribute changes the implicit [prelude] from `std` to `core`,
|
||||
/// which may affect the paths you need to use in other probes. It also
|
||||
/// restricts some types that otherwise get additional methods in `std`,
|
||||
/// like floating-point trigonometry and slice sorting.
|
||||
///
|
||||
/// See also [`set_no_std`](#method.set_no_std).
|
||||
///
|
||||
/// [prelude]: https://doc.rust-lang.org/reference/names/preludes.html#the-no_std-attribute
|
||||
pub fn no_std(&self) -> bool {
|
||||
self.no_std
|
||||
}
|
||||
|
||||
/// Sets whether `AutoCfg` should use `#![no_std]` in its probes.
|
||||
///
|
||||
/// See also [`no_std`](#method.no_std).
|
||||
pub fn set_no_std(&mut self, no_std: bool) {
|
||||
self.no_std = no_std;
|
||||
}
|
||||
|
||||
/// Tests whether the current `rustc` reports a version greater than
|
||||
/// or equal to "`major`.`minor`".
|
||||
pub fn probe_rustc_version(&self, major: usize, minor: usize) -> bool {
|
||||
self.rustc_version >= Version::new(major, minor, 0)
|
||||
@@ -197,20 +255,27 @@ impl AutoCfg {
|
||||
/// Sets a `cfg` value of the form `rustc_major_minor`, like `rustc_1_29`,
|
||||
/// if the current `rustc` is at least that version.
|
||||
pub fn emit_rustc_version(&self, major: usize, minor: usize) {
|
||||
let cfg_flag = format!("rustc_{}_{}", major, minor);
|
||||
emit_possibility(&cfg_flag);
|
||||
if self.probe_rustc_version(major, minor) {
|
||||
emit(&format!("rustc_{}_{}", major, minor));
|
||||
emit(&cfg_flag);
|
||||
}
|
||||
}
|
||||
|
||||
fn probe<T: AsRef<[u8]>>(&self, code: T) -> Result<bool, Error> {
|
||||
/// Returns a new (hopefully unique) crate name for probes.
|
||||
fn new_crate_name(&self) -> String {
|
||||
#[allow(deprecated)]
|
||||
static ID: AtomicUsize = ATOMIC_USIZE_INIT;
|
||||
|
||||
let id = ID.fetch_add(1, Ordering::Relaxed);
|
||||
let mut command = Command::new(&self.rustc);
|
||||
format!("autocfg_{:016x}_{}", self.uuid, id)
|
||||
}
|
||||
|
||||
fn probe_fmt<'a>(&self, source: Arguments<'a>) -> Result<(), Error> {
|
||||
let mut command = self.rustc.command();
|
||||
command
|
||||
.arg("--crate-name")
|
||||
.arg(format!("probe{}", id))
|
||||
.arg(self.new_crate_name())
|
||||
.arg("--crate-type=lib")
|
||||
.arg("--out-dir")
|
||||
.arg(&self.out_dir)
|
||||
@@ -226,14 +291,71 @@ impl AutoCfg {
|
||||
let mut child = try!(command.spawn().map_err(error::from_io));
|
||||
let mut stdin = child.stdin.take().expect("rustc stdin");
|
||||
|
||||
if self.no_std {
|
||||
try!(stdin.write_all(b"#![no_std]\n").map_err(error::from_io));
|
||||
}
|
||||
try!(stdin.write_all(code.as_ref()).map_err(error::from_io));
|
||||
try!(stdin.write_fmt(source).map_err(error::from_io));
|
||||
drop(stdin);
|
||||
|
||||
let status = try!(child.wait().map_err(error::from_io));
|
||||
Ok(status.success())
|
||||
match child.wait() {
|
||||
Ok(status) if status.success() => Ok(()),
|
||||
Ok(status) => Err(error::from_exit(status)),
|
||||
Err(error) => Err(error::from_io(error)),
|
||||
}
|
||||
}
|
||||
|
||||
fn probe<'a>(&self, code: Arguments<'a>) -> bool {
|
||||
let result = if self.no_std {
|
||||
self.probe_fmt(format_args!("#![no_std]\n{}", code))
|
||||
} else {
|
||||
self.probe_fmt(code)
|
||||
};
|
||||
result.is_ok()
|
||||
}
|
||||
|
||||
/// Tests whether the given code can be compiled as a Rust library.
|
||||
///
|
||||
/// This will only return `Ok` if the compiler ran and exited successfully,
|
||||
/// per `ExitStatus::success()`.
|
||||
/// The code is passed to the compiler exactly as-is, notably not even
|
||||
/// adding the [`#![no_std]`][Self::no_std] attribute like other probes.
|
||||
///
|
||||
/// Raw probes are useful for testing functionality that's not yet covered
|
||||
/// by the rest of the `AutoCfg` API. For example, the following attribute
|
||||
/// **must** be used at the crate level, so it wouldn't work within the code
|
||||
/// templates used by other `probe_*` methods.
|
||||
///
|
||||
/// ```
|
||||
/// # extern crate autocfg;
|
||||
/// # // Normally, cargo will set `OUT_DIR` for build scripts.
|
||||
/// # let exe = std::env::current_exe().unwrap();
|
||||
/// # std::env::set_var("OUT_DIR", exe.parent().unwrap());
|
||||
/// let ac = autocfg::new();
|
||||
/// assert!(ac.probe_raw("#![no_builtins]").is_ok());
|
||||
/// ```
|
||||
///
|
||||
/// Rust nightly features could be tested as well -- ideally including a
|
||||
/// code sample to ensure the unstable feature still works as expected.
|
||||
/// For example, `slice::group_by` was renamed to `chunk_by` when it was
|
||||
/// stabilized, even though the feature name was unchanged, so testing the
|
||||
/// `#![feature(..)]` alone wouldn't reveal that. For larger snippets,
|
||||
/// [`include_str!`] may be useful to load them from separate files.
|
||||
///
|
||||
/// ```
|
||||
/// # extern crate autocfg;
|
||||
/// # // Normally, cargo will set `OUT_DIR` for build scripts.
|
||||
/// # let exe = std::env::current_exe().unwrap();
|
||||
/// # std::env::set_var("OUT_DIR", exe.parent().unwrap());
|
||||
/// let ac = autocfg::new();
|
||||
/// let code = r#"
|
||||
/// #![feature(slice_group_by)]
|
||||
/// pub fn probe(slice: &[i32]) -> impl Iterator<Item = &[i32]> {
|
||||
/// slice.group_by(|a, b| a == b)
|
||||
/// }
|
||||
/// "#;
|
||||
/// if ac.probe_raw(code).is_ok() {
|
||||
/// autocfg::emit("has_slice_group_by");
|
||||
/// }
|
||||
/// ```
|
||||
pub fn probe_raw(&self, code: &str) -> Result<(), Error> {
|
||||
self.probe_fmt(format_args!("{}", code))
|
||||
}
|
||||
|
||||
/// Tests whether the given sysroot crate can be used.
|
||||
@@ -244,14 +366,16 @@ impl AutoCfg {
|
||||
/// extern crate CRATE as probe;
|
||||
/// ```
|
||||
pub fn probe_sysroot_crate(&self, name: &str) -> bool {
|
||||
self.probe(format!("extern crate {} as probe;", name)) // `as _` wasn't stabilized until Rust 1.33
|
||||
.unwrap_or(false)
|
||||
// Note: `as _` wasn't stabilized until Rust 1.33
|
||||
self.probe(format_args!("extern crate {} as probe;", name))
|
||||
}
|
||||
|
||||
/// Emits a config value `has_CRATE` if `probe_sysroot_crate` returns true.
|
||||
pub fn emit_sysroot_crate(&self, name: &str) {
|
||||
let cfg_flag = format!("has_{}", mangle(name));
|
||||
emit_possibility(&cfg_flag);
|
||||
if self.probe_sysroot_crate(name) {
|
||||
emit(&format!("has_{}", mangle(name)));
|
||||
emit(&cfg_flag);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,7 +387,7 @@ impl AutoCfg {
|
||||
/// pub use PATH;
|
||||
/// ```
|
||||
pub fn probe_path(&self, path: &str) -> bool {
|
||||
self.probe(format!("pub use {};", path)).unwrap_or(false)
|
||||
self.probe(format_args!("pub use {};", path))
|
||||
}
|
||||
|
||||
/// Emits a config value `has_PATH` if `probe_path` returns true.
|
||||
@@ -271,13 +395,12 @@ impl AutoCfg {
|
||||
/// Any non-identifier characters in the `path` will be replaced with
|
||||
/// `_` in the generated config value.
|
||||
pub fn emit_has_path(&self, path: &str) {
|
||||
if self.probe_path(path) {
|
||||
emit(&format!("has_{}", mangle(path)));
|
||||
}
|
||||
self.emit_path_cfg(path, &format!("has_{}", mangle(path)));
|
||||
}
|
||||
|
||||
/// Emits the given `cfg` value if `probe_path` returns true.
|
||||
pub fn emit_path_cfg(&self, path: &str, cfg: &str) {
|
||||
emit_possibility(cfg);
|
||||
if self.probe_path(path) {
|
||||
emit(cfg);
|
||||
}
|
||||
@@ -291,8 +414,7 @@ impl AutoCfg {
|
||||
/// pub trait Probe: TRAIT + Sized {}
|
||||
/// ```
|
||||
pub fn probe_trait(&self, name: &str) -> bool {
|
||||
self.probe(format!("pub trait Probe: {} + Sized {{}}", name))
|
||||
.unwrap_or(false)
|
||||
self.probe(format_args!("pub trait Probe: {} + Sized {{}}", name))
|
||||
}
|
||||
|
||||
/// Emits a config value `has_TRAIT` if `probe_trait` returns true.
|
||||
@@ -300,13 +422,12 @@ impl AutoCfg {
|
||||
/// Any non-identifier characters in the trait `name` will be replaced with
|
||||
/// `_` in the generated config value.
|
||||
pub fn emit_has_trait(&self, name: &str) {
|
||||
if self.probe_trait(name) {
|
||||
emit(&format!("has_{}", mangle(name)));
|
||||
}
|
||||
self.emit_trait_cfg(name, &format!("has_{}", mangle(name)));
|
||||
}
|
||||
|
||||
/// Emits the given `cfg` value if `probe_trait` returns true.
|
||||
pub fn emit_trait_cfg(&self, name: &str, cfg: &str) {
|
||||
emit_possibility(cfg);
|
||||
if self.probe_trait(name) {
|
||||
emit(cfg);
|
||||
}
|
||||
@@ -320,8 +441,7 @@ impl AutoCfg {
|
||||
/// pub type Probe = TYPE;
|
||||
/// ```
|
||||
pub fn probe_type(&self, name: &str) -> bool {
|
||||
self.probe(format!("pub type Probe = {};", name))
|
||||
.unwrap_or(false)
|
||||
self.probe(format_args!("pub type Probe = {};", name))
|
||||
}
|
||||
|
||||
/// Emits a config value `has_TYPE` if `probe_type` returns true.
|
||||
@@ -329,13 +449,12 @@ impl AutoCfg {
|
||||
/// Any non-identifier characters in the type `name` will be replaced with
|
||||
/// `_` in the generated config value.
|
||||
pub fn emit_has_type(&self, name: &str) {
|
||||
if self.probe_type(name) {
|
||||
emit(&format!("has_{}", mangle(name)));
|
||||
}
|
||||
self.emit_type_cfg(name, &format!("has_{}", mangle(name)));
|
||||
}
|
||||
|
||||
/// Emits the given `cfg` value if `probe_type` returns true.
|
||||
pub fn emit_type_cfg(&self, name: &str, cfg: &str) {
|
||||
emit_possibility(cfg);
|
||||
if self.probe_type(name) {
|
||||
emit(cfg);
|
||||
}
|
||||
@@ -349,12 +468,12 @@ impl AutoCfg {
|
||||
/// pub fn probe() { let _ = EXPR; }
|
||||
/// ```
|
||||
pub fn probe_expression(&self, expr: &str) -> bool {
|
||||
self.probe(format!("pub fn probe() {{ let _ = {}; }}", expr))
|
||||
.unwrap_or(false)
|
||||
self.probe(format_args!("pub fn probe() {{ let _ = {}; }}", expr))
|
||||
}
|
||||
|
||||
/// Emits the given `cfg` value if `probe_expression` returns true.
|
||||
pub fn emit_expression_cfg(&self, expr: &str, cfg: &str) {
|
||||
emit_possibility(cfg);
|
||||
if self.probe_expression(expr) {
|
||||
emit(cfg);
|
||||
}
|
||||
@@ -368,12 +487,12 @@ impl AutoCfg {
|
||||
/// pub const PROBE: () = ((), EXPR).0;
|
||||
/// ```
|
||||
pub fn probe_constant(&self, expr: &str) -> bool {
|
||||
self.probe(format!("pub const PROBE: () = ((), {}).0;", expr))
|
||||
.unwrap_or(false)
|
||||
self.probe(format_args!("pub const PROBE: () = ((), {}).0;", expr))
|
||||
}
|
||||
|
||||
/// Emits the given `cfg` value if `probe_constant` returns true.
|
||||
pub fn emit_constant_cfg(&self, expr: &str, cfg: &str) {
|
||||
emit_possibility(cfg);
|
||||
if self.probe_constant(expr) {
|
||||
emit(cfg);
|
||||
}
|
||||
@@ -405,7 +524,7 @@ fn dir_contains_target(
|
||||
|
||||
cargo_target_dir
|
||||
.to_str()
|
||||
.map(|cargo_target_dir| dir.contains(&cargo_target_dir))
|
||||
.map(|cargo_target_dir| dir.contains(cargo_target_dir))
|
||||
})
|
||||
})
|
||||
.unwrap_or(false)
|
||||
@@ -451,3 +570,21 @@ fn rustflags(target: &Option<OsString>, dir: &Path) -> Vec<String> {
|
||||
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
/// Generates a numeric ID to use in probe crate names.
|
||||
///
|
||||
/// This attempts to be random, within the constraints of Rust 1.0 and no dependencies.
|
||||
fn new_uuid() -> u64 {
|
||||
const FNV_OFFSET_BASIS: u64 = 0xcbf2_9ce4_8422_2325;
|
||||
const FNV_PRIME: u64 = 0x100_0000_01b3;
|
||||
|
||||
// This set should have an actual random hasher.
|
||||
let set: std::collections::HashSet<u64> = (0..256).collect();
|
||||
|
||||
// Feed the `HashSet`-shuffled order into FNV-1a.
|
||||
let mut hash: u64 = FNV_OFFSET_BASIS;
|
||||
for x in set {
|
||||
hash = (hash ^ x).wrapping_mul(FNV_PRIME);
|
||||
}
|
||||
hash
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
use super::error::Error;
|
||||
use super::version::Version;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Rustc {
|
||||
rustc: PathBuf,
|
||||
rustc_wrapper: Option<PathBuf>,
|
||||
rustc_workspace_wrapper: Option<PathBuf>,
|
||||
}
|
||||
|
||||
impl Rustc {
|
||||
pub fn new() -> Self {
|
||||
Rustc {
|
||||
rustc: env::var_os("RUSTC")
|
||||
.unwrap_or_else(|| "rustc".into())
|
||||
.into(),
|
||||
rustc_wrapper: get_rustc_wrapper(false),
|
||||
rustc_workspace_wrapper: get_rustc_wrapper(true),
|
||||
}
|
||||
}
|
||||
|
||||
/// Build the command with possible wrappers.
|
||||
pub fn command(&self) -> Command {
|
||||
let mut rustc = self
|
||||
.rustc_wrapper
|
||||
.iter()
|
||||
.chain(self.rustc_workspace_wrapper.iter())
|
||||
.chain(Some(&self.rustc));
|
||||
let mut command = Command::new(rustc.next().unwrap());
|
||||
for arg in rustc {
|
||||
command.arg(arg);
|
||||
}
|
||||
command
|
||||
}
|
||||
|
||||
/// Try to get the `rustc` version.
|
||||
pub fn version(&self) -> Result<Version, Error> {
|
||||
// Some wrappers like clippy-driver don't pass through version commands,
|
||||
// so we try to fall back to combinations without each wrapper.
|
||||
macro_rules! try_version {
|
||||
($command:expr) => {
|
||||
if let Ok(value) = Version::from_command($command) {
|
||||
return Ok(value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let rustc = &self.rustc;
|
||||
if let Some(ref rw) = self.rustc_wrapper {
|
||||
if let Some(ref rww) = self.rustc_workspace_wrapper {
|
||||
try_version!(Command::new(rw).args(&[rww, rustc]));
|
||||
}
|
||||
try_version!(Command::new(rw).arg(rustc));
|
||||
}
|
||||
if let Some(ref rww) = self.rustc_workspace_wrapper {
|
||||
try_version!(Command::new(rww).arg(rustc));
|
||||
}
|
||||
Version::from_command(&mut Command::new(rustc))
|
||||
}
|
||||
}
|
||||
|
||||
fn get_rustc_wrapper(workspace: bool) -> Option<PathBuf> {
|
||||
// We didn't really know whether the workspace wrapper is applicable until Cargo started
|
||||
// deliberately setting or unsetting it in rust-lang/cargo#9601. We'll use the encoded
|
||||
// rustflags as a proxy for that change for now, but we could instead check version 1.55.
|
||||
if workspace && env::var_os("CARGO_ENCODED_RUSTFLAGS").is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let name = if workspace {
|
||||
"RUSTC_WORKSPACE_WRAPPER"
|
||||
} else {
|
||||
"RUSTC_WRAPPER"
|
||||
};
|
||||
|
||||
if let Some(wrapper) = env::var_os(name) {
|
||||
// NB: `OsStr` didn't get `len` or `is_empty` until 1.9.
|
||||
if wrapper != OsString::new() {
|
||||
return Some(wrapper.into());
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
-120
@@ -1,36 +1,5 @@
|
||||
use super::AutoCfg;
|
||||
use std::env;
|
||||
use std::path::Path;
|
||||
|
||||
impl AutoCfg {
|
||||
fn core_std(&self, path: &str) -> String {
|
||||
let krate = if self.no_std { "core" } else { "std" };
|
||||
format!("{}::{}", krate, path)
|
||||
}
|
||||
|
||||
fn assert_std(&self, probe_result: bool) {
|
||||
assert_eq!(!self.no_std, probe_result);
|
||||
}
|
||||
|
||||
fn assert_min(&self, major: usize, minor: usize, probe_result: bool) {
|
||||
assert_eq!(self.probe_rustc_version(major, minor), probe_result);
|
||||
}
|
||||
|
||||
fn for_test() -> Result<Self, super::error::Error> {
|
||||
match env::var_os("TESTS_TARGET_DIR") {
|
||||
Some(d) => Self::with_dir(d),
|
||||
None => Self::with_dir("target"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn autocfg_version() {
|
||||
let ac = AutoCfg::for_test().unwrap();
|
||||
println!("version: {:?}", ac.rustc_version);
|
||||
assert!(ac.probe_rustc_version(1, 0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn version_cmp() {
|
||||
use super::version::Version;
|
||||
@@ -44,95 +13,6 @@ fn version_cmp() {
|
||||
assert!(Version::new(2, 0, 0) > v123);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn probe_add() {
|
||||
let ac = AutoCfg::for_test().unwrap();
|
||||
let add = ac.core_std("ops::Add");
|
||||
let add_rhs = add.clone() + "<i32>";
|
||||
let add_rhs_output = add.clone() + "<i32, Output = i32>";
|
||||
let dyn_add_rhs_output = "dyn ".to_string() + &*add_rhs_output;
|
||||
assert!(ac.probe_path(&add));
|
||||
assert!(ac.probe_trait(&add));
|
||||
assert!(ac.probe_trait(&add_rhs));
|
||||
assert!(ac.probe_trait(&add_rhs_output));
|
||||
ac.assert_min(1, 27, ac.probe_type(&dyn_add_rhs_output));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn probe_as_ref() {
|
||||
let ac = AutoCfg::for_test().unwrap();
|
||||
let as_ref = ac.core_std("convert::AsRef");
|
||||
let as_ref_str = as_ref.clone() + "<str>";
|
||||
let dyn_as_ref_str = "dyn ".to_string() + &*as_ref_str;
|
||||
assert!(ac.probe_path(&as_ref));
|
||||
assert!(ac.probe_trait(&as_ref_str));
|
||||
assert!(ac.probe_type(&as_ref_str));
|
||||
ac.assert_min(1, 27, ac.probe_type(&dyn_as_ref_str));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn probe_i128() {
|
||||
let ac = AutoCfg::for_test().unwrap();
|
||||
let i128_path = ac.core_std("i128");
|
||||
ac.assert_min(1, 26, ac.probe_path(&i128_path));
|
||||
ac.assert_min(1, 26, ac.probe_type("i128"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn probe_sum() {
|
||||
let ac = AutoCfg::for_test().unwrap();
|
||||
let sum = ac.core_std("iter::Sum");
|
||||
let sum_i32 = sum.clone() + "<i32>";
|
||||
let dyn_sum_i32 = "dyn ".to_string() + &*sum_i32;
|
||||
ac.assert_min(1, 12, ac.probe_path(&sum));
|
||||
ac.assert_min(1, 12, ac.probe_trait(&sum));
|
||||
ac.assert_min(1, 12, ac.probe_trait(&sum_i32));
|
||||
ac.assert_min(1, 12, ac.probe_type(&sum_i32));
|
||||
ac.assert_min(1, 27, ac.probe_type(&dyn_sum_i32));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn probe_std() {
|
||||
let ac = AutoCfg::for_test().unwrap();
|
||||
ac.assert_std(ac.probe_sysroot_crate("std"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn probe_alloc() {
|
||||
let ac = AutoCfg::for_test().unwrap();
|
||||
ac.assert_min(1, 36, ac.probe_sysroot_crate("alloc"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn probe_bad_sysroot_crate() {
|
||||
let ac = AutoCfg::for_test().unwrap();
|
||||
assert!(!ac.probe_sysroot_crate("doesnt_exist"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn probe_no_std() {
|
||||
let ac = AutoCfg::for_test().unwrap();
|
||||
assert!(ac.probe_type("i32"));
|
||||
assert!(ac.probe_type("[i32]"));
|
||||
ac.assert_std(ac.probe_type("Vec<i32>"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn probe_expression() {
|
||||
let ac = AutoCfg::for_test().unwrap();
|
||||
assert!(ac.probe_expression(r#""test".trim_left()"#));
|
||||
ac.assert_min(1, 30, ac.probe_expression(r#""test".trim_start()"#));
|
||||
ac.assert_std(ac.probe_expression("[1, 2, 3].to_vec()"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn probe_constant() {
|
||||
let ac = AutoCfg::for_test().unwrap();
|
||||
assert!(ac.probe_constant("1 + 2 + 3"));
|
||||
ac.assert_min(1, 33, ac.probe_constant("{ let x = 1 + 2 + 3; x * x }"));
|
||||
ac.assert_min(1, 39, ac.probe_constant(r#""test".len()"#));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dir_does_not_contain_target() {
|
||||
assert!(!super::dir_contains_target(
|
||||
|
||||
+11
-6
@@ -1,4 +1,3 @@
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
use std::str;
|
||||
|
||||
@@ -22,9 +21,9 @@ impl Version {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_rustc(rustc: &Path) -> Result<Self, Error> {
|
||||
pub fn from_command(command: &mut Command) -> Result<Self, Error> {
|
||||
// Get rustc's verbose version
|
||||
let output = try!(Command::new(rustc)
|
||||
let output = try!(command
|
||||
.args(&["--version", "--verbose"])
|
||||
.output()
|
||||
.map_err(error::from_io));
|
||||
@@ -47,9 +46,15 @@ impl Version {
|
||||
|
||||
// Split the version into semver components.
|
||||
let mut iter = version.splitn(3, '.');
|
||||
let major = try!(iter.next().ok_or(error::from_str("missing major version")));
|
||||
let minor = try!(iter.next().ok_or(error::from_str("missing minor version")));
|
||||
let patch = try!(iter.next().ok_or(error::from_str("missing patch version")));
|
||||
let major = try!(iter
|
||||
.next()
|
||||
.ok_or_else(|| error::from_str("missing major version")));
|
||||
let minor = try!(iter
|
||||
.next()
|
||||
.ok_or_else(|| error::from_str("missing minor version")));
|
||||
let patch = try!(iter
|
||||
.next()
|
||||
.ok_or_else(|| error::from_str("missing patch version")));
|
||||
|
||||
Ok(Version::new(
|
||||
try!(major.parse().map_err(error::from_num)),
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
extern crate autocfg;
|
||||
|
||||
use std::env;
|
||||
|
||||
mod support;
|
||||
|
||||
/// Tests that we can control the use of `#![no_std]`.
|
||||
#[test]
|
||||
fn no_std() {
|
||||
// Clear the CI `TARGET`, if any, so we're just dealing with the
|
||||
// host target which always has `std` available.
|
||||
env::remove_var("TARGET");
|
||||
|
||||
// Use the same path as this test binary.
|
||||
let out = support::out_dir();
|
||||
|
||||
let mut ac = autocfg::AutoCfg::with_dir(out.as_ref()).unwrap();
|
||||
assert!(!ac.no_std());
|
||||
assert!(ac.probe_path("std::mem"));
|
||||
|
||||
// `#![no_std]` was stabilized in Rust 1.6
|
||||
if ac.probe_rustc_version(1, 6) {
|
||||
ac.set_no_std(true);
|
||||
assert!(ac.no_std());
|
||||
assert!(!ac.probe_path("std::mem"));
|
||||
assert!(ac.probe_path("core::mem"));
|
||||
}
|
||||
}
|
||||
+7
-6
@@ -2,18 +2,19 @@ extern crate autocfg;
|
||||
|
||||
use std::env;
|
||||
|
||||
mod support;
|
||||
|
||||
/// Tests that autocfg uses the RUSTFLAGS or CARGO_ENCODED_RUSTFLAGS
|
||||
/// environment variables when running rustc.
|
||||
#[test]
|
||||
fn test_with_sysroot() {
|
||||
// Use the same path as this test binary.
|
||||
let dir = env::current_exe().unwrap().parent().unwrap().to_path_buf();
|
||||
env::set_var("OUT_DIR", &format!("{}", dir.display()));
|
||||
let dir = support::exe_dir();
|
||||
let out = support::out_dir();
|
||||
|
||||
// If we have encoded rustflags, they take precedence, even if empty.
|
||||
env::set_var("CARGO_ENCODED_RUSTFLAGS", "");
|
||||
env::set_var("RUSTFLAGS", &format!("-L {}", dir.display()));
|
||||
let ac = autocfg::AutoCfg::new().unwrap();
|
||||
let ac = autocfg::AutoCfg::with_dir(out.as_ref()).unwrap();
|
||||
assert!(ac.probe_sysroot_crate("std"));
|
||||
assert!(!ac.probe_sysroot_crate("autocfg"));
|
||||
|
||||
@@ -22,12 +23,12 @@ fn test_with_sysroot() {
|
||||
"CARGO_ENCODED_RUSTFLAGS",
|
||||
&format!("-L\x1f{}", dir.display()),
|
||||
);
|
||||
let ac = autocfg::AutoCfg::new().unwrap();
|
||||
let ac = autocfg::AutoCfg::with_dir(out.as_ref()).unwrap();
|
||||
assert!(ac.probe_sysroot_crate("autocfg"));
|
||||
|
||||
// Try the old-style RUSTFLAGS, ensuring HOST != TARGET.
|
||||
env::remove_var("CARGO_ENCODED_RUSTFLAGS");
|
||||
env::set_var("HOST", "lol");
|
||||
let ac = autocfg::AutoCfg::new().unwrap();
|
||||
let ac = autocfg::AutoCfg::with_dir(out.as_ref()).unwrap();
|
||||
assert!(ac.probe_sysroot_crate("autocfg"));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
use std::borrow::Cow;
|
||||
use std::env;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
/// The directory containing this test binary.
|
||||
pub fn exe_dir() -> PathBuf {
|
||||
let exe = env::current_exe().unwrap();
|
||||
exe.parent().unwrap().to_path_buf()
|
||||
}
|
||||
|
||||
/// The directory to use for test probes.
|
||||
pub fn out_dir() -> Cow<'static, Path> {
|
||||
if let Some(tmpdir) = option_env!("CARGO_TARGET_TMPDIR") {
|
||||
Cow::Borrowed(tmpdir.as_ref())
|
||||
} else if let Some(tmpdir) = env::var_os("TESTS_TARGET_DIR") {
|
||||
Cow::Owned(tmpdir.into())
|
||||
} else {
|
||||
// Use the same path as this test binary.
|
||||
Cow::Owned(exe_dir())
|
||||
}
|
||||
}
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
extern crate autocfg;
|
||||
|
||||
use autocfg::AutoCfg;
|
||||
|
||||
mod support;
|
||||
|
||||
fn core_std(ac: &AutoCfg, path: &str) -> String {
|
||||
let krate = if ac.no_std() { "core" } else { "std" };
|
||||
format!("{}::{}", krate, path)
|
||||
}
|
||||
|
||||
fn assert_std(ac: &AutoCfg, probe_result: bool) {
|
||||
assert_eq!(!ac.no_std(), probe_result);
|
||||
}
|
||||
|
||||
fn assert_min(ac: &AutoCfg, major: usize, minor: usize, probe_result: bool) {
|
||||
assert_eq!(ac.probe_rustc_version(major, minor), probe_result);
|
||||
}
|
||||
|
||||
fn autocfg_for_test() -> AutoCfg {
|
||||
AutoCfg::with_dir(support::out_dir().as_ref()).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn autocfg_version() {
|
||||
let ac = autocfg_for_test();
|
||||
assert!(ac.probe_rustc_version(1, 0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn probe_add() {
|
||||
let ac = autocfg_for_test();
|
||||
let add = core_std(&ac, "ops::Add");
|
||||
let add_rhs = add.clone() + "<i32>";
|
||||
let add_rhs_output = add.clone() + "<i32, Output = i32>";
|
||||
let dyn_add_rhs_output = "dyn ".to_string() + &*add_rhs_output;
|
||||
assert!(ac.probe_path(&add));
|
||||
assert!(ac.probe_trait(&add));
|
||||
assert!(ac.probe_trait(&add_rhs));
|
||||
assert!(ac.probe_trait(&add_rhs_output));
|
||||
assert_min(&ac, 1, 27, ac.probe_type(&dyn_add_rhs_output));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn probe_as_ref() {
|
||||
let ac = autocfg_for_test();
|
||||
let as_ref = core_std(&ac, "convert::AsRef");
|
||||
let as_ref_str = as_ref.clone() + "<str>";
|
||||
let dyn_as_ref_str = "dyn ".to_string() + &*as_ref_str;
|
||||
assert!(ac.probe_path(&as_ref));
|
||||
assert!(ac.probe_trait(&as_ref_str));
|
||||
assert!(ac.probe_type(&as_ref_str));
|
||||
assert_min(&ac, 1, 27, ac.probe_type(&dyn_as_ref_str));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn probe_i128() {
|
||||
let ac = autocfg_for_test();
|
||||
let i128_path = core_std(&ac, "i128");
|
||||
assert_min(&ac, 1, 26, ac.probe_path(&i128_path));
|
||||
assert_min(&ac, 1, 26, ac.probe_type("i128"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn probe_sum() {
|
||||
let ac = autocfg_for_test();
|
||||
let sum = core_std(&ac, "iter::Sum");
|
||||
let sum_i32 = sum.clone() + "<i32>";
|
||||
let dyn_sum_i32 = "dyn ".to_string() + &*sum_i32;
|
||||
assert_min(&ac, 1, 12, ac.probe_path(&sum));
|
||||
assert_min(&ac, 1, 12, ac.probe_trait(&sum));
|
||||
assert_min(&ac, 1, 12, ac.probe_trait(&sum_i32));
|
||||
assert_min(&ac, 1, 12, ac.probe_type(&sum_i32));
|
||||
assert_min(&ac, 1, 27, ac.probe_type(&dyn_sum_i32));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn probe_std() {
|
||||
let ac = autocfg_for_test();
|
||||
assert_std(&ac, ac.probe_sysroot_crate("std"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn probe_alloc() {
|
||||
let ac = autocfg_for_test();
|
||||
assert_min(&ac, 1, 36, ac.probe_sysroot_crate("alloc"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn probe_bad_sysroot_crate() {
|
||||
let ac = autocfg_for_test();
|
||||
assert!(!ac.probe_sysroot_crate("doesnt_exist"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn probe_no_std() {
|
||||
let ac = autocfg_for_test();
|
||||
assert!(ac.probe_type("i32"));
|
||||
assert!(ac.probe_type("[i32]"));
|
||||
assert_std(&ac, ac.probe_type("Vec<i32>"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn probe_expression() {
|
||||
let ac = autocfg_for_test();
|
||||
assert!(ac.probe_expression(r#""test".trim_left()"#));
|
||||
assert_min(&ac, 1, 30, ac.probe_expression(r#""test".trim_start()"#));
|
||||
assert_std(&ac, ac.probe_expression("[1, 2, 3].to_vec()"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn probe_constant() {
|
||||
let ac = autocfg_for_test();
|
||||
assert!(ac.probe_constant("1 + 2 + 3"));
|
||||
assert_min(
|
||||
&ac,
|
||||
1,
|
||||
33,
|
||||
ac.probe_constant("{ let x = 1 + 2 + 3; x * x }"),
|
||||
);
|
||||
assert_min(&ac, 1, 39, ac.probe_constant(r#""test".len()"#));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn probe_raw() {
|
||||
let ac = autocfg_for_test();
|
||||
let prefix = if ac.no_std() { "#![no_std]\n" } else { "" };
|
||||
let f = |s| format!("{}{}", prefix, s);
|
||||
|
||||
// This attribute **must** be used at the crate level.
|
||||
assert!(ac.probe_raw(&f("#![no_builtins]")).is_ok());
|
||||
|
||||
assert!(ac.probe_raw(&f("#![deny(dead_code)] fn x() {}")).is_err());
|
||||
assert!(ac.probe_raw(&f("#![allow(dead_code)] fn x() {}")).is_ok());
|
||||
assert!(ac
|
||||
.probe_raw(&f("#![deny(dead_code)] pub fn x() {}"))
|
||||
.is_ok());
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
# Add our own version so we can check that the wrapper is used for that.
|
||||
"--version") echo "release: 12345.6789.0" ;;
|
||||
# Read all input so the writer doesn't get EPIPE when we exit.
|
||||
"-") read -d "" PROBE ;;
|
||||
esac
|
||||
done
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,56 @@
|
||||
extern crate autocfg;
|
||||
|
||||
use std::env;
|
||||
|
||||
mod support;
|
||||
|
||||
/// Tests that autocfg uses the RUSTC_WRAPPER and/or RUSTC_WORKSPACE_WRAPPER
|
||||
/// environment variables when running rustc.
|
||||
#[test]
|
||||
#[cfg(unix)] // we're using system binaries as wrappers
|
||||
fn test_wrappers() {
|
||||
fn set(name: &str, value: Option<bool>) {
|
||||
match value {
|
||||
Some(true) => env::set_var(name, "/usr/bin/env"),
|
||||
Some(false) => env::set_var(name, "/bin/false"),
|
||||
None => env::remove_var(name),
|
||||
}
|
||||
}
|
||||
|
||||
let out = support::out_dir();
|
||||
|
||||
// This is used as a heuristic to detect rust-lang/cargo#9601.
|
||||
env::set_var("CARGO_ENCODED_RUSTFLAGS", "");
|
||||
|
||||
// No wrapper, a good pass-through wrapper, and a bad wrapper.
|
||||
let variants = [None, Some(true), Some(false)];
|
||||
|
||||
for &workspace in &variants {
|
||||
for &rustc in &variants {
|
||||
set("RUSTC_WRAPPER", rustc);
|
||||
set("RUSTC_WORKSPACE_WRAPPER", workspace);
|
||||
|
||||
let ac = autocfg::AutoCfg::with_dir(out.as_ref()).unwrap();
|
||||
if rustc == Some(false) || workspace == Some(false) {
|
||||
// Everything should fail with bad wrappers.
|
||||
assert!(!ac.probe_type("usize"));
|
||||
} else {
|
||||
// Try known good and bad types for the wrapped rustc.
|
||||
assert!(ac.probe_type("usize"));
|
||||
assert!(!ac.probe_type("mesize"));
|
||||
}
|
||||
// Either way, we should have found the inner rustc version.
|
||||
assert!(ac.probe_rustc_version(1, 0));
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, make sure that `RUSTC_WRAPPER` is applied outermost
|
||||
// by using something that doesn't pass through at all.
|
||||
env::set_var("RUSTC_WRAPPER", "./tests/wrap_ignored");
|
||||
env::set_var("RUSTC_WORKSPACE_WRAPPER", "/bin/false");
|
||||
let ac = autocfg::AutoCfg::with_dir(out.as_ref()).unwrap();
|
||||
assert!(ac.probe_type("mesize")); // anything goes!
|
||||
|
||||
// Make sure we also got the version from that wrapper.
|
||||
assert!(ac.probe_rustc_version(12345, 6789));
|
||||
}
|
||||
Reference in New Issue
Block a user