mirror of
https://github.com/rust-lang/cargo.git
synced 2025-10-01 11:30:39 +00:00
Migrate build-rs to the Cargo repo (#14786)
### What does this PR try to resolve? Fixes #12432 ### How should we test and review this PR? This pulls in https://github.com/cad97/build-rs at eb389d1104dae2dc2eb4eafa9d6e821a7dcb45a7 with the following changes: - `Cargo.toml` metadata - Removal of `.github`, `.gitignore`, `Cargo.lock` We'll need to integrate `test-lib` into our processes but that seemed more invasive, so I wanted to leave that for a future PR. ### Additional information Infra changes are being coordinated in https://rust-lang.zulipchat.com/#narrow/channel/242791-t-infra/topic/Transfering.20.60build-rs.60.20crate.20to.20rust-lang/near/480779960 Context: per [Cargo's charter](https://doc.crates.io/contrib/team.html#decision-process), we approved this transfer in an [FCP](https://github.com/rust-lang/cargo/issues/12432#issuecomment-2389528102).
This commit is contained in:
commit
e5ce5e5588
18
Cargo.lock
generated
18
Cargo.lock
generated
@ -252,6 +252,20 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "build-rs"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "build-rs-test-lib"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"build-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.16.0"
|
||||
@ -3760,9 +3774,9 @@ checksum = "7eec5d1121208364f6793f7d2e222bf75a915c19557537745b195b253dd64217"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
|
@ -24,6 +24,7 @@ anstyle = "1.0.8"
|
||||
anyhow = "1.0.86"
|
||||
base64 = "0.22.1"
|
||||
blake3 = "1.5.2"
|
||||
build-rs = { version = "0.2.0", path = "crates/build-rs" }
|
||||
bytesize = "1.3"
|
||||
cargo = { path = "" }
|
||||
cargo-credential = { version = "0.4.2", path = "credential/cargo-credential" }
|
||||
@ -107,6 +108,7 @@ tracing = { version = "0.1.40", default-features = false, features = ["std"] } #
|
||||
tracing-chrome = "0.7.2"
|
||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
||||
unicase = "2.7.0"
|
||||
unicode-ident = "1.0.13"
|
||||
unicode-width = "0.2.0"
|
||||
unicode-xid = "0.2.4"
|
||||
url = "2.5.2"
|
||||
|
11
crates/build-rs-test-lib/Cargo.toml
Normal file
11
crates/build-rs-test-lib/Cargo.toml
Normal file
@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "build-rs-test-lib"
|
||||
version = "0.0.0"
|
||||
edition.workspace = true
|
||||
publish = false
|
||||
|
||||
[features]
|
||||
unstable = ["build-rs/unstable"]
|
||||
|
||||
[build-dependencies]
|
||||
build-rs.workspace = true
|
78
crates/build-rs-test-lib/build.rs
Normal file
78
crates/build-rs-test-lib/build.rs
Normal file
@ -0,0 +1,78 @@
|
||||
fn main() {
|
||||
smoke_test_inputs();
|
||||
|
||||
build_rs::output::rerun_if_changed("build.rs");
|
||||
build_rs::output::rustc_check_cfgs(&["did_run_build_script"]);
|
||||
build_rs::output::rustc_cfg("did_run_build_script");
|
||||
}
|
||||
|
||||
fn smoke_test_inputs() {
|
||||
use build_rs::input::*;
|
||||
dbg!(cargo());
|
||||
dbg!(cargo_cfg("careful"));
|
||||
dbg!(cargo_cfg_debug_assertions());
|
||||
#[cfg(feature = "unstable")]
|
||||
dbg!(cargo_cfg_fmt_debug());
|
||||
#[cfg(feature = "unstable")]
|
||||
dbg!(cargo_cfg_overflow_checks());
|
||||
dbg!(cargo_cfg_panic());
|
||||
dbg!(cargo_cfg_proc_macro());
|
||||
#[cfg(feature = "unstable")]
|
||||
dbg!(cargo_cfg_relocation_model());
|
||||
#[cfg(feature = "unstable")]
|
||||
dbg!(cargo_cfg_sanitize());
|
||||
#[cfg(feature = "unstable")]
|
||||
dbg!(cargo_cfg_sanitizer_cfi_generalize_pointers());
|
||||
#[cfg(feature = "unstable")]
|
||||
dbg!(cargo_cfg_sanitizer_cfi_normalize_integers());
|
||||
dbg!(cargo_cfg_target_abi());
|
||||
dbg!(cargo_cfg_target_arch());
|
||||
dbg!(cargo_cfg_target_endian());
|
||||
dbg!(cargo_cfg_target_env());
|
||||
dbg!(cargo_cfg_target_feature());
|
||||
dbg!(cargo_cfg_target_has_atomic());
|
||||
#[cfg(feature = "unstable")]
|
||||
dbg!(cargo_cfg_target_has_atomic_equal_alignment());
|
||||
#[cfg(feature = "unstable")]
|
||||
dbg!(cargo_cfg_target_has_atomic_load_store());
|
||||
dbg!(cargo_cfg_target_os());
|
||||
dbg!(cargo_cfg_target_pointer_width());
|
||||
#[cfg(feature = "unstable")]
|
||||
dbg!(cargo_cfg_target_thread_local());
|
||||
dbg!(cargo_cfg_target_vendor());
|
||||
#[cfg(feature = "unstable")]
|
||||
dbg!(cargo_cfg_ub_checks());
|
||||
dbg!(cargo_cfg_unix());
|
||||
dbg!(cargo_cfg_windows());
|
||||
dbg!(cargo_encoded_rustflags());
|
||||
dbg!(cargo_feature("unstable"));
|
||||
dbg!(cargo_manifest_dir());
|
||||
dbg!(cargo_manifest_links());
|
||||
dbg!(cargo_pkg_authors());
|
||||
dbg!(cargo_pkg_description());
|
||||
dbg!(cargo_pkg_homepage());
|
||||
dbg!(cargo_pkg_license());
|
||||
dbg!(cargo_pkg_license_file());
|
||||
dbg!(cargo_pkg_name());
|
||||
dbg!(cargo_pkg_readme());
|
||||
dbg!(cargo_pkg_repository());
|
||||
dbg!(cargo_pkg_rust_version());
|
||||
dbg!(cargo_pkg_version());
|
||||
dbg!(cargo_pkg_version_major());
|
||||
dbg!(cargo_pkg_version_minor());
|
||||
dbg!(cargo_pkg_version_patch());
|
||||
dbg!(cargo_pkg_version_pre());
|
||||
dbg!(debug());
|
||||
dbg!(dep_metadata("z", "include"));
|
||||
dbg!(host());
|
||||
dbg!(num_jobs());
|
||||
dbg!(opt_level());
|
||||
dbg!(out_dir());
|
||||
dbg!(profile());
|
||||
dbg!(rustc());
|
||||
dbg!(rustc_linker());
|
||||
dbg!(rustc_workspace_wrapper());
|
||||
dbg!(rustc_wrapper());
|
||||
dbg!(rustdoc());
|
||||
dbg!(target());
|
||||
}
|
4
crates/build-rs-test-lib/src/lib.rs
Normal file
4
crates/build-rs-test-lib/src/lib.rs
Normal file
@ -0,0 +1,4 @@
|
||||
#[test]
|
||||
fn test() {
|
||||
assert!(cfg!(did_run_build_script));
|
||||
}
|
16
crates/build-rs/Cargo.toml
Normal file
16
crates/build-rs/Cargo.toml
Normal file
@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "build-rs"
|
||||
version = "0.2.0"
|
||||
rust-version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
homepage.workspace = true
|
||||
repository.workspace = true
|
||||
description = "API for writing Cargo `build.rs` files"
|
||||
|
||||
[features]
|
||||
## Experimental API. This feature flag is **NOT** semver stable.
|
||||
unstable = []
|
||||
|
||||
[dependencies]
|
||||
unicode-ident.workspace = true
|
2
crates/build-rs/README.md
Normal file
2
crates/build-rs/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
> This crate is maintained by the Cargo team for use by the wider
|
||||
> ecosystem. This crate follows semver compatibility for its APIs.
|
46
crates/build-rs/src/allow_use.rs
Normal file
46
crates/build-rs/src/allow_use.rs
Normal file
@ -0,0 +1,46 @@
|
||||
use std::{process::Command, sync::OnceLock};
|
||||
|
||||
fn rust_version_minor() -> u32 {
|
||||
static VERSION_MINOR: OnceLock<u32> = OnceLock::new();
|
||||
*VERSION_MINOR.get_or_init(|| {
|
||||
crate::input::cargo_pkg_rust_version()
|
||||
.split('.')
|
||||
.nth(1)
|
||||
// assume build-rs's MSRV if none specified for the current package
|
||||
.unwrap_or(env!("CARGO_PKG_RUST_VERSION").split('.').nth(1).unwrap())
|
||||
.parse()
|
||||
.unwrap()
|
||||
})
|
||||
}
|
||||
|
||||
fn cargo_version_minor() -> u32 {
|
||||
static VERSION_MINOR: OnceLock<u32> = OnceLock::new();
|
||||
*VERSION_MINOR.get_or_init(|| {
|
||||
let out = Command::new(crate::input::cargo())
|
||||
.arg("-V")
|
||||
.output()
|
||||
.expect("running `cargo -V` should succeed");
|
||||
assert!(out.status.success(), "running `cargo -V` should succeed");
|
||||
|
||||
// > cargo -V # example output
|
||||
// cargo 1.82.0 (8f40fc59f 2024-08-21)
|
||||
|
||||
String::from_utf8(out.stdout).expect("`cargo -V` should output valid UTF-8")
|
||||
["cargo 1.".len()..]
|
||||
.split('.')
|
||||
.next()
|
||||
.expect("`cargo -V` format should be stable")
|
||||
.parse()
|
||||
.unwrap()
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn double_colon_directives() -> bool {
|
||||
// cargo errors on `cargo::` directives with insufficient package.rust-version
|
||||
rust_version_minor() >= 77
|
||||
}
|
||||
|
||||
pub(crate) fn check_cfg() -> bool {
|
||||
// emit check-cfg if the toolchain being used supports it
|
||||
cargo_version_minor() >= 80
|
||||
}
|
27
crates/build-rs/src/ident.rs
Normal file
27
crates/build-rs/src/ident.rs
Normal file
@ -0,0 +1,27 @@
|
||||
use unicode_ident::{is_xid_continue, is_xid_start};
|
||||
|
||||
pub(crate) fn is_feature_name(s: &str) -> bool {
|
||||
s.chars()
|
||||
.all(|ch| is_xid_continue(ch) || matches!(ch, '-' | '+' | '.'))
|
||||
}
|
||||
|
||||
pub(crate) fn is_ident(s: &str) -> bool {
|
||||
let mut cs = s.chars();
|
||||
cs.next()
|
||||
.is_some_and(|ch| is_xid_start(ch) || matches!(ch, '_'))
|
||||
&& cs.all(is_xid_continue)
|
||||
}
|
||||
|
||||
pub(crate) fn is_ascii_ident(s: &str) -> bool {
|
||||
let mut cs = s.chars();
|
||||
cs.next()
|
||||
.is_some_and(|ch| ch.is_ascii_alphabetic() || matches!(ch, '_'))
|
||||
&& cs.all(|ch| ch.is_ascii_alphanumeric() || matches!(ch, '_'))
|
||||
}
|
||||
|
||||
pub(crate) fn is_crate_name(s: &str) -> bool {
|
||||
let mut cs = s.chars();
|
||||
cs.next()
|
||||
.is_some_and(|ch| is_xid_start(ch) || matches!(ch, '-' | '_'))
|
||||
&& cs.all(|ch| is_xid_continue(ch) || matches!(ch, '-'))
|
||||
}
|
591
crates/build-rs/src/input.rs
Normal file
591
crates/build-rs/src/input.rs
Normal file
@ -0,0 +1,591 @@
|
||||
//! Inputs from the build system to the build script.
|
||||
//!
|
||||
//! This crate does not do any caching or interpreting of the values provided by
|
||||
//! Cargo beyond the communication protocol itself. It is up to the build script
|
||||
//! to interpret the string values and decide what to do with them.
|
||||
//!
|
||||
//! Reference: <https://doc.rust-lang.org/stable/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts>
|
||||
|
||||
use crate::ident::{is_ascii_ident, is_crate_name, is_feature_name};
|
||||
use std::{
|
||||
env,
|
||||
fmt::Display,
|
||||
path::PathBuf,
|
||||
str::{self, FromStr},
|
||||
};
|
||||
|
||||
macro_rules! missing {
|
||||
($key:expr) => {
|
||||
panic!("cargo environment variable `{}` is missing", $key)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! invalid {
|
||||
($key:expr, $err:expr) => {
|
||||
panic!("cargo environment variable `{}` is invalid: {}", $key, $err)
|
||||
};
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn get_bool(key: &str) -> bool {
|
||||
env::var_os(key).is_some()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn get_opt_path(key: &str) -> Option<PathBuf> {
|
||||
let var = env::var_os(key)?;
|
||||
Some(PathBuf::from(var))
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn get_path(key: &str) -> PathBuf {
|
||||
get_opt_path(key).unwrap_or_else(|| missing!(key))
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn get_opt_str(key: &str) -> Option<String> {
|
||||
let var = env::var_os(key)?;
|
||||
match str::from_utf8(var.as_encoded_bytes()) {
|
||||
Ok(s) => Some(s.to_owned()),
|
||||
Err(err) => invalid!(key, err),
|
||||
}
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn get_str(key: &str) -> String {
|
||||
get_opt_str(key).unwrap_or_else(|| missing!(key))
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn get_num<T: FromStr>(key: &str) -> T
|
||||
where
|
||||
T::Err: Display,
|
||||
{
|
||||
let val = get_str(key);
|
||||
match val.parse() {
|
||||
Ok(num) => num,
|
||||
Err(err) => invalid!(key, err),
|
||||
}
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn get_opt_cfg(cfg: &str) -> (String, Option<Vec<String>>) {
|
||||
if !is_ascii_ident(cfg) {
|
||||
panic!("invalid configuration option {cfg:?}")
|
||||
}
|
||||
let cfg = cfg.to_uppercase().replace('-', "_");
|
||||
let key = format!("CARGO_CFG_{cfg}");
|
||||
let Some(var) = env::var_os(&key) else {
|
||||
return (key, None);
|
||||
};
|
||||
let val = str::from_utf8(var.as_encoded_bytes()).unwrap_or_else(|err| invalid!(key, err));
|
||||
(key, Some(val.split(',').map(str::to_owned).collect()))
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn get_cfg(cfg: &str) -> Vec<String> {
|
||||
let (key, val) = get_opt_cfg(cfg);
|
||||
val.unwrap_or_else(|| missing!(key))
|
||||
}
|
||||
|
||||
// docs last updated to match release 1.82.0 reference
|
||||
|
||||
/// Path to the `cargo` binary performing the build.
|
||||
#[track_caller]
|
||||
pub fn cargo() -> PathBuf {
|
||||
get_path("CARGO")
|
||||
}
|
||||
|
||||
/// The directory containing the manifest for the package being built (the package
|
||||
/// containing the build script). Also note that this is the value of the current
|
||||
/// working directory of the build script when it starts.
|
||||
#[track_caller]
|
||||
pub fn cargo_manifest_dir() -> PathBuf {
|
||||
get_path("CARGO_MANIFEST_DIR")
|
||||
}
|
||||
|
||||
/// Contains parameters needed for Cargo’s [jobserver] implementation to parallelize
|
||||
/// subprocesses. Rustc or cargo invocations from build.rs can already read
|
||||
/// `CARGO_MAKEFLAGS`, but GNU Make requires the flags to be specified either
|
||||
/// directly as arguments, or through the `MAKEFLAGS` environment variable.
|
||||
/// Currently Cargo doesn’t set the `MAKEFLAGS` variable, but it’s free for build
|
||||
/// scripts invoking GNU Make to set it to the contents of `CARGO_MAKEFLAGS`.
|
||||
///
|
||||
/// [jobserver]: https://www.gnu.org/software/make/manual/html_node/Job-Slots.html
|
||||
#[track_caller]
|
||||
pub fn cargo_manifest_links() -> Option<String> {
|
||||
get_opt_str("CARGO_MANIFEST_LINKS")
|
||||
}
|
||||
|
||||
/// For each activated feature of the package being built, this will be `true`.
|
||||
#[track_caller]
|
||||
pub fn cargo_feature(name: &str) -> bool {
|
||||
if !is_feature_name(name) {
|
||||
panic!("invalid feature name {name:?}")
|
||||
}
|
||||
let name = name.to_uppercase().replace('-', "_");
|
||||
let key = format!("CARGO_FEATURE_{name}");
|
||||
get_bool(&key)
|
||||
}
|
||||
|
||||
/// For each [configuration option] of the package being built, this will contain
|
||||
/// the value of the configuration. This includes values built-in to the compiler
|
||||
/// (which can be seen with `rustc --print=cfg`) and values set by build scripts
|
||||
/// and extra flags passed to rustc (such as those defined in `RUSTFLAGS`).
|
||||
///
|
||||
/// [configuration option]: https://doc.rust-lang.org/stable/reference/conditional-compilation.html
|
||||
#[track_caller]
|
||||
pub fn cargo_cfg(cfg: &str) -> Option<Vec<String>> {
|
||||
let (_, val) = get_opt_cfg(cfg);
|
||||
val
|
||||
}
|
||||
|
||||
pub use self::cfg::*;
|
||||
mod cfg {
|
||||
use super::*;
|
||||
|
||||
// those disabled with #[cfg(any())] don't seem meaningfully useful
|
||||
// but we list all cfg that are default known to check-cfg
|
||||
|
||||
#[cfg(any())]
|
||||
#[track_caller]
|
||||
pub fn cargo_cfg_clippy() -> bool {
|
||||
get_bool("CARGO_CFG_CLIPPY")
|
||||
}
|
||||
|
||||
/// If we are compiling with debug assertions enabled.
|
||||
#[track_caller]
|
||||
pub fn cargo_cfg_debug_assertions() -> bool {
|
||||
get_bool("CARGO_CFG_DEBUG_ASSERTIONS")
|
||||
}
|
||||
|
||||
#[cfg(any())]
|
||||
#[track_caller]
|
||||
pub fn cargo_cfg_doc() -> bool {
|
||||
get_bool("CARGO_CFG_DOC")
|
||||
}
|
||||
|
||||
#[cfg(any())]
|
||||
#[track_caller]
|
||||
pub fn cargo_cfg_docsrs() -> bool {
|
||||
get_bool("CARGO_CFG_DOCSRS")
|
||||
}
|
||||
|
||||
#[cfg(any())]
|
||||
#[track_caller]
|
||||
pub fn cargo_cfg_doctest() -> bool {
|
||||
get_bool("CARGO_CFG_DOCTEST")
|
||||
}
|
||||
|
||||
/// The level of detail provided by derived [`Debug`] implementations.
|
||||
#[doc = unstable!(fmt_dbg, 129709)]
|
||||
#[cfg(feature = "unstable")]
|
||||
#[track_caller]
|
||||
pub fn cargo_cfg_fmt_debug() -> String {
|
||||
get_str("CARGO_CFG_FMT_DEBUG")
|
||||
}
|
||||
|
||||
#[cfg(any())]
|
||||
#[track_caller]
|
||||
pub fn cargo_cfg_miri() -> bool {
|
||||
get_bool("CARGO_CFG_MIRI")
|
||||
}
|
||||
|
||||
/// If we are compiling with overflow checks enabled.
|
||||
#[doc = unstable!(cfg_overflow_checks, 111466)]
|
||||
#[cfg(feature = "unstable")]
|
||||
#[track_caller]
|
||||
pub fn cargo_cfg_overflow_checks() -> bool {
|
||||
get_bool("CARGO_CFG_OVERFLOW_CHECKS")
|
||||
}
|
||||
|
||||
/// The [panic strategy](https://doc.rust-lang.org/stable/reference/conditional-compilation.html#panic).
|
||||
#[track_caller]
|
||||
pub fn cargo_cfg_panic() -> String {
|
||||
get_str("CARGO_CFG_PANIC")
|
||||
}
|
||||
|
||||
/// If the crate is being compiled as a procedural macro.
|
||||
#[track_caller]
|
||||
pub fn cargo_cfg_proc_macro() -> bool {
|
||||
get_bool("CARGO_CFG_PROC_MACRO")
|
||||
}
|
||||
|
||||
/// The target relocation model.
|
||||
#[doc = unstable!(cfg_relocation_model, 114929)]
|
||||
#[cfg(feature = "unstable")]
|
||||
#[track_caller]
|
||||
pub fn cargo_cfg_relocation_model() -> String {
|
||||
get_str("CARGO_CFG_RELOCATION_MODEL")
|
||||
}
|
||||
|
||||
#[cfg(any())]
|
||||
#[track_caller]
|
||||
pub fn cargo_cfg_rustfmt() -> bool {
|
||||
get_bool("CARGO_CFG_RUSTFMT")
|
||||
}
|
||||
|
||||
/// Sanitizers enabled for the crate being compiled.
|
||||
#[doc = unstable!(cfg_sanitize, 39699)]
|
||||
#[cfg(feature = "unstable")]
|
||||
#[track_caller]
|
||||
pub fn cargo_cfg_sanitize() -> Option<Vec<String>> {
|
||||
let (_, val) = get_opt_cfg("CARGO_CFG_SANITIZE");
|
||||
val
|
||||
}
|
||||
|
||||
/// If CFI sanitization is generalizing pointers.
|
||||
#[doc = unstable!(cfg_sanitizer_cfi, 89653)]
|
||||
#[cfg(feature = "unstable")]
|
||||
#[track_caller]
|
||||
pub fn cargo_cfg_sanitizer_cfi_generalize_pointers() -> bool {
|
||||
get_bool("CARGO_CFG_SANITIZER_CFI_GENERALIZE_POINTERS")
|
||||
}
|
||||
|
||||
/// If CFI sanitization is normalizing integers.
|
||||
#[doc = unstable!(cfg_sanitizer_cfi, 89653)]
|
||||
#[cfg(feature = "unstable")]
|
||||
#[track_caller]
|
||||
pub fn cargo_cfg_sanitizer_cfi_normalize_integers() -> bool {
|
||||
get_bool("CARGO_CFG_SANITIZER_CFI_NORMALIZE_INTEGERS")
|
||||
}
|
||||
|
||||
/// Disambiguation of the [target ABI](https://doc.rust-lang.org/stable/reference/conditional-compilation.html#target_abi)
|
||||
/// when the [target env](cargo_cfg_target_env) isn't sufficient.
|
||||
///
|
||||
/// For historical reasons, this value is only defined as not the empty-string when
|
||||
/// actually needed for disambiguation. Thus, for example, on many GNU platforms,
|
||||
/// this value will be empty.
|
||||
#[track_caller]
|
||||
pub fn cargo_cfg_target_abi() -> String {
|
||||
get_str("CARGO_CFG_TARGET_ABI")
|
||||
}
|
||||
|
||||
/// The CPU [target architecture](https://doc.rust-lang.org/stable/reference/conditional-compilation.html#target_arch).
|
||||
/// This is similar to the first element of the platform's target triple, but not identical.
|
||||
#[track_caller]
|
||||
pub fn cargo_cfg_target_arch() -> String {
|
||||
get_str("CARGO_CFG_TARGET_ARCH")
|
||||
}
|
||||
|
||||
/// The CPU [target endianness](https://doc.rust-lang.org/stable/reference/conditional-compilation.html#target_endian).
|
||||
#[track_caller]
|
||||
pub fn cargo_cfg_target_endian() -> String {
|
||||
get_str("CARGO_CFG_TARGET_ENDIAN")
|
||||
}
|
||||
|
||||
/// The [target environment](https://doc.rust-lang.org/stable/reference/conditional-compilation.html#target_env) ABI.
|
||||
/// This value is similar to the fourth element of the platform's target triple.
|
||||
///
|
||||
/// For historical reasons, this value is only defined as not the empty-string when
|
||||
/// actually needed for disambiguation. Thus, for example, on many GNU platforms,
|
||||
/// this value will be empty.
|
||||
#[track_caller]
|
||||
pub fn cargo_cfg_target_env() -> String {
|
||||
get_str("CARGO_CFG_TARGET_ENV")
|
||||
}
|
||||
|
||||
/// The [target family](https://doc.rust-lang.org/stable/reference/conditional-compilation.html#target_family).
|
||||
#[track_caller]
|
||||
pub fn cargo_target_family() -> Vec<String> {
|
||||
get_cfg("target_family")
|
||||
}
|
||||
|
||||
/// List of CPU [target features](https://doc.rust-lang.org/stable/reference/conditional-compilation.html#target_feature) enabled.
|
||||
#[track_caller]
|
||||
pub fn cargo_cfg_target_feature() -> Vec<String> {
|
||||
get_cfg("target_feature")
|
||||
}
|
||||
|
||||
/// List of CPU [supported atomic widths](https://doc.rust-lang.org/stable/reference/conditional-compilation.html#target_has_atomic).
|
||||
#[track_caller]
|
||||
pub fn cargo_cfg_target_has_atomic() -> Vec<String> {
|
||||
get_cfg("target_has_atomic")
|
||||
}
|
||||
|
||||
/// List of atomic widths that have equal alignment requirements.
|
||||
#[doc = unstable!(cfg_target_has_atomic_equal_alignment, 93822)]
|
||||
#[cfg(feature = "unstable")]
|
||||
#[track_caller]
|
||||
pub fn cargo_cfg_target_has_atomic_equal_alignment() -> Vec<String> {
|
||||
get_cfg("target_has_atomic_equal_alignment")
|
||||
}
|
||||
|
||||
/// List of atomic widths that have atomic load and store operations.
|
||||
#[doc = unstable!(cfg_target_has_atomic_load_store, 94039)]
|
||||
#[cfg(feature = "unstable")]
|
||||
#[track_caller]
|
||||
pub fn cargo_cfg_target_has_atomic_load_store() -> Vec<String> {
|
||||
get_cfg("target_has_atomic_load_store")
|
||||
}
|
||||
|
||||
/// The [target operating system](https://doc.rust-lang.org/stable/reference/conditional-compilation.html#target_os).
|
||||
/// This value is similar to the second and third element of the platform's target triple.
|
||||
#[track_caller]
|
||||
pub fn cargo_cfg_target_os() -> String {
|
||||
get_str("CARGO_CFG_TARGET_OS")
|
||||
}
|
||||
|
||||
/// The CPU [pointer width](https://doc.rust-lang.org/stable/reference/conditional-compilation.html#target_pointer_width).
|
||||
#[track_caller]
|
||||
pub fn cargo_cfg_target_pointer_width() -> u32 {
|
||||
get_num("CARGO_CFG_TARGET_POINTER_WIDTH")
|
||||
}
|
||||
|
||||
/// If the target supports thread-local storage.
|
||||
#[doc = unstable!(cfg_target_thread_local, 29594)]
|
||||
#[cfg(feature = "unstable")]
|
||||
#[track_caller]
|
||||
pub fn cargo_cfg_target_thread_local() -> bool {
|
||||
get_bool("CARGO_CFG_TARGET_THREAD_LOCAL")
|
||||
}
|
||||
|
||||
/// The [target vendor](https://doc.rust-lang.org/stable/reference/conditional-compilation.html#target_vendor).
|
||||
#[track_caller]
|
||||
pub fn cargo_cfg_target_vendor() -> String {
|
||||
get_str("CARGO_CFG_TARGET_VENDOR")
|
||||
}
|
||||
|
||||
#[cfg(any())]
|
||||
#[track_caller]
|
||||
pub fn cargo_cfg_test() -> bool {
|
||||
get_bool("CARGO_CFG_TEST")
|
||||
}
|
||||
|
||||
/// If we are compiling with UB checks enabled.
|
||||
#[doc = unstable!(cfg_ub_checks, 123499)]
|
||||
#[cfg(feature = "unstable")]
|
||||
#[track_caller]
|
||||
pub fn cargo_cfg_ub_checks() -> bool {
|
||||
get_bool("CARGO_CFG_UB_CHECKS")
|
||||
}
|
||||
|
||||
/// Set on [unix-like platforms](https://doc.rust-lang.org/stable/reference/conditional-compilation.html#unix-and-windows).
|
||||
#[track_caller]
|
||||
pub fn cargo_cfg_unix() -> bool {
|
||||
get_bool("CARGO_CFG_UNIX")
|
||||
}
|
||||
|
||||
/// Set on [windows-like platforms](https://doc.rust-lang.org/stable/reference/conditional-compilation.html#unix-and-windows).
|
||||
#[track_caller]
|
||||
pub fn cargo_cfg_windows() -> bool {
|
||||
get_bool("CARGO_CFG_WINDOWS")
|
||||
}
|
||||
}
|
||||
|
||||
/// The folder in which all output and intermediate artifacts should be placed.
|
||||
/// This folder is inside the build directory for the package being built, and
|
||||
/// it is unique for the package in question.
|
||||
#[track_caller]
|
||||
pub fn out_dir() -> PathBuf {
|
||||
get_path("OUT_DIR")
|
||||
}
|
||||
|
||||
/// The [target triple] that is being compiled for. Native code should be compiled
|
||||
/// for this triple.
|
||||
///
|
||||
/// [target triple]: https://doc.rust-lang.org/stable/cargo/appendix/glossary.html#target
|
||||
#[track_caller]
|
||||
pub fn target() -> String {
|
||||
get_str("TARGET")
|
||||
}
|
||||
|
||||
/// The host triple of the Rust compiler.
|
||||
#[track_caller]
|
||||
pub fn host() -> String {
|
||||
get_str("HOST")
|
||||
}
|
||||
|
||||
/// The parallelism specified as the top-level parallelism. This can be useful to
|
||||
/// pass a `-j` parameter to a system like `make`. Note that care should be taken
|
||||
/// when interpreting this value. For historical purposes this is still provided
|
||||
/// but Cargo, for example, does not need to run `make -j`, and instead can set the
|
||||
/// `MAKEFLAGS` env var to the content of `CARGO_MAKEFLAGS` to activate the use of
|
||||
/// Cargo’s GNU Make compatible [jobserver] for sub-make invocations.
|
||||
///
|
||||
/// [jobserver]: https://www.gnu.org/software/make/manual/html_node/Job-Slots.html
|
||||
#[track_caller]
|
||||
pub fn num_jobs() -> u32 {
|
||||
get_num("NUM_JOBS")
|
||||
}
|
||||
|
||||
/// The [level of optimization](https://doc.rust-lang.org/stable/cargo/reference/profiles.html#opt-level).
|
||||
#[track_caller]
|
||||
pub fn opt_level() -> String {
|
||||
get_str("OPT_LEVEL")
|
||||
}
|
||||
|
||||
/// The amount of [debug information](https://doc.rust-lang.org/stable/cargo/reference/profiles.html#debug) included.
|
||||
#[track_caller]
|
||||
pub fn debug() -> String {
|
||||
get_str("DEBUG")
|
||||
}
|
||||
|
||||
/// `release` for release builds, `debug` for other builds. This is determined based
|
||||
/// on if the [profile] inherits from the [`dev`] or [`release`] profile. Using this
|
||||
/// function is not recommended. Using other functions like [`opt_level`] provides
|
||||
/// a more correct view of the actual settings being used.
|
||||
///
|
||||
/// [profile]: https://doc.rust-lang.org/stable/cargo/reference/profiles.html
|
||||
/// [`dev`]: https://doc.rust-lang.org/stable/cargo/reference/profiles.html#dev
|
||||
/// [`release`]: https://doc.rust-lang.org/stable/cargo/reference/profiles.html#release
|
||||
#[track_caller]
|
||||
pub fn profile() -> String {
|
||||
get_str("PROFILE")
|
||||
}
|
||||
|
||||
/// [Metadata] set by dependencies. For more information, see build script
|
||||
/// documentation about [the `links` manifest key][links].
|
||||
///
|
||||
/// [metadata]: crate::output::metadata
|
||||
/// [links]: https://doc.rust-lang.org/stable/cargo/reference/build-scripts.html#the-links-manifest-key
|
||||
#[track_caller]
|
||||
pub fn dep_metadata(name: &str, key: &str) -> Option<String> {
|
||||
if !is_crate_name(name) {
|
||||
panic!("invalid dependency name {name:?}")
|
||||
}
|
||||
if !is_ascii_ident(key) {
|
||||
panic!("invalid metadata key {key:?}")
|
||||
}
|
||||
|
||||
let name = name.to_uppercase().replace('-', "_");
|
||||
let key = key.to_uppercase().replace('-', "_");
|
||||
let key = format!("DEP_{name}_{key}");
|
||||
get_opt_str(&key)
|
||||
}
|
||||
|
||||
/// The compiler that Cargo has resolved to use.
|
||||
#[track_caller]
|
||||
pub fn rustc() -> PathBuf {
|
||||
get_path("RUSTC")
|
||||
}
|
||||
|
||||
/// The documentation generator that Cargo has resolved to use.
|
||||
#[track_caller]
|
||||
pub fn rustdoc() -> PathBuf {
|
||||
get_path("RUSTDOC")
|
||||
}
|
||||
|
||||
/// The rustc wrapper, if any, that Cargo is using. See [`build.rustc-wrapper`].
|
||||
///
|
||||
/// [`build.rustc-wrapper`]: https://doc.rust-lang.org/stable/cargo/reference/config.html#buildrustc-wrapper
|
||||
#[track_caller]
|
||||
pub fn rustc_wrapper() -> Option<PathBuf> {
|
||||
get_opt_path("RUSTC_WRAPPER")
|
||||
}
|
||||
|
||||
/// The rustc wrapper, if any, that Cargo is using for workspace members. See
|
||||
/// [`build.rustc-workspace-wrapper`].
|
||||
///
|
||||
/// [`build.rustc-workspace-wrapper`]: https://doc.rust-lang.org/stable/cargo/reference/config.html#buildrustc-workspace-wrapper
|
||||
#[track_caller]
|
||||
pub fn rustc_workspace_wrapper() -> Option<PathBuf> {
|
||||
get_opt_path("RUSTC_WORKSPACE_WRAPPER")
|
||||
}
|
||||
|
||||
/// The linker that Cargo has resolved to use for the current target, if specified.
|
||||
///
|
||||
/// [`target.*.linker`]: https://doc.rust-lang.org/stable/cargo/reference/config.html#targettriplelinker
|
||||
#[track_caller]
|
||||
pub fn rustc_linker() -> Option<PathBuf> {
|
||||
get_opt_path("RUSTC_LINKER")
|
||||
}
|
||||
|
||||
/// Extra flags that Cargo invokes rustc with. See [`build.rustflags`].
|
||||
///
|
||||
/// [`build.rustflags`]: https://doc.rust-lang.org/stable/cargo/reference/config.html#buildrustflags
|
||||
#[track_caller]
|
||||
pub fn cargo_encoded_rustflags() -> Vec<String> {
|
||||
get_str("CARGO_ENCODED_RUSTFLAGS")
|
||||
.split('\x1f')
|
||||
.map(str::to_owned)
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// The full version of your package.
|
||||
#[track_caller]
|
||||
pub fn cargo_pkg_version() -> String {
|
||||
get_str("CARGO_PKG_VERSION")
|
||||
}
|
||||
|
||||
/// The major version of your package.
|
||||
#[track_caller]
|
||||
pub fn cargo_pkg_version_major() -> u64 {
|
||||
get_num("CARGO_PKG_VERSION_MAJOR")
|
||||
}
|
||||
|
||||
/// The minor version of your package.
|
||||
#[track_caller]
|
||||
pub fn cargo_pkg_version_minor() -> u64 {
|
||||
get_num("CARGO_PKG_VERSION_MINOR")
|
||||
}
|
||||
|
||||
/// The patch version of your package.
|
||||
#[track_caller]
|
||||
pub fn cargo_pkg_version_patch() -> u64 {
|
||||
get_num("CARGO_PKG_VERSION_PATCH")
|
||||
}
|
||||
|
||||
/// The pre-release version of your package.
|
||||
#[track_caller]
|
||||
pub fn cargo_pkg_version_pre() -> String {
|
||||
get_str("CARGO_PKG_VERSION_PRE")
|
||||
}
|
||||
|
||||
/// Colon separated list of authors from the manifest of your package.
|
||||
#[track_caller]
|
||||
pub fn cargo_pkg_authors() -> Vec<String> {
|
||||
get_str("CARGO_PKG_AUTHORS")
|
||||
.split(':')
|
||||
.map(str::to_owned)
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// The name of your package.
|
||||
#[track_caller]
|
||||
pub fn cargo_pkg_name() -> String {
|
||||
get_str("CARGO_PKG_NAME")
|
||||
}
|
||||
|
||||
/// The description from the manifest of your package.
|
||||
#[track_caller]
|
||||
pub fn cargo_pkg_description() -> String {
|
||||
get_str("CARGO_PKG_DESCRIPTION")
|
||||
}
|
||||
|
||||
/// The home page from the manifest of your package.
|
||||
#[track_caller]
|
||||
pub fn cargo_pkg_homepage() -> String {
|
||||
get_str("CARGO_PKG_HOMEPAGE")
|
||||
}
|
||||
|
||||
/// The repository from the manifest of your package.
|
||||
#[track_caller]
|
||||
pub fn cargo_pkg_repository() -> String {
|
||||
get_str("CARGO_PKG_REPOSITORY")
|
||||
}
|
||||
|
||||
/// The license from the manifest of your package.
|
||||
#[track_caller]
|
||||
pub fn cargo_pkg_license() -> String {
|
||||
get_str("CARGO_PKG_LICENSE")
|
||||
}
|
||||
|
||||
/// The license file from the manifest of your package.
|
||||
#[track_caller]
|
||||
pub fn cargo_pkg_license_file() -> PathBuf {
|
||||
get_path("CARGO_PKG_LICENSE_FILE")
|
||||
}
|
||||
|
||||
/// The Rust version from the manifest of your package. Note that this is the
|
||||
/// minimum Rust version supported by the package, not the current Rust version.
|
||||
#[track_caller]
|
||||
pub fn cargo_pkg_rust_version() -> String {
|
||||
get_str("CARGO_PKG_RUST_VERSION")
|
||||
}
|
||||
|
||||
/// Path to the README file of your package.
|
||||
#[track_caller]
|
||||
pub fn cargo_pkg_readme() -> PathBuf {
|
||||
get_path("CARGO_PKG_README")
|
||||
}
|
39
crates/build-rs/src/lib.rs
Normal file
39
crates/build-rs/src/lib.rs
Normal file
@ -0,0 +1,39 @@
|
||||
//! build-rs provides a strongly typed interface around the Cargo build script
|
||||
//! protocol. Cargo provides inputs to the build script by environment variable
|
||||
//! and accepts commands by printing to stdout.
|
||||
//!
|
||||
//! > This crate is maintained by the Cargo team for use by the wider
|
||||
//! > ecosystem. This crate follows semver compatibility for its APIs.
|
||||
#![cfg_attr(all(doc, feature = "unstable"), feature(doc_auto_cfg, doc_cfg))]
|
||||
#![allow(clippy::disallowed_methods)] // HACK: deferred resoling this
|
||||
#![allow(clippy::print_stdout)] // HACK: deferred resoling this
|
||||
|
||||
#[cfg(feature = "unstable")]
|
||||
macro_rules! unstable {
|
||||
($feature:ident, $issue:literal) => {
|
||||
concat!(
|
||||
r#"<div class="stab unstable">"#,
|
||||
r#"<span class="emoji">🔬</span>"#,
|
||||
r#"<span>This is a nightly-only experimental API. (<code>"#,
|
||||
stringify!($feature),
|
||||
r#"</code> <a href="https://github.com/rust-lang/rust/issues/"#,
|
||||
$issue,
|
||||
r#"">#"#,
|
||||
$issue,
|
||||
r#"</a>)</span>"#,
|
||||
r#"</div>"#
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! msrv {
|
||||
($ver:literal) => {
|
||||
concat!("> MSRV: Respected as of ", $ver, ".")
|
||||
};
|
||||
}
|
||||
|
||||
mod allow_use;
|
||||
mod ident;
|
||||
|
||||
pub mod input;
|
||||
pub mod output;
|
408
crates/build-rs/src/output.rs
Normal file
408
crates/build-rs/src/output.rs
Normal file
@ -0,0 +1,408 @@
|
||||
//! Outputs from the build script to the build system.
|
||||
//!
|
||||
//! This crate assumes that stdout is at a new line whenever an output directive
|
||||
//! is called. Printing to stdout without a terminating newline (i.e. not using
|
||||
//! [`println!`]) may lead to surprising behavior.
|
||||
//!
|
||||
//! Reference: <https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script>
|
||||
|
||||
use crate::{
|
||||
allow_use,
|
||||
ident::{is_ascii_ident, is_ident},
|
||||
};
|
||||
use std::{ffi::OsStr, fmt::Display, fmt::Write, path::Path, str};
|
||||
|
||||
fn emit(directive: &str, value: impl Display) {
|
||||
if allow_use::double_colon_directives() {
|
||||
println!("cargo::{}={}", directive, value);
|
||||
} else {
|
||||
println!("cargo:{}={}", directive, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// The `rerun-if-changed` instruction tells Cargo to re-run the build script if the
|
||||
/// file at the given path has changed. Currently, Cargo only uses the filesystem
|
||||
/// last-modified “mtime” timestamp to determine if the file has changed. It
|
||||
/// compares against an internal cached timestamp of when the build script last ran.
|
||||
///
|
||||
/// If the path points to a directory, it will scan the entire directory for any
|
||||
/// modifications.
|
||||
///
|
||||
/// If the build script inherently does not need to re-run under any circumstance,
|
||||
/// then calling `rerun_if_changed("build.rs")` is a simple way to prevent it from
|
||||
/// being re-run (otherwise, the default if no `rerun-if` instructions are emitted
|
||||
/// is to scan the entire package directory for changes). Cargo automatically
|
||||
/// handles whether or not the script itself needs to be recompiled, and of course
|
||||
/// the script will be re-run after it has been recompiled. Otherwise, specifying
|
||||
/// `build.rs` is redundant and unnecessary.
|
||||
#[track_caller]
|
||||
pub fn rerun_if_changed(path: impl AsRef<Path>) {
|
||||
let Some(path) = path.as_ref().to_str() else {
|
||||
panic!("cannot emit rerun-if-changed: path is not UTF-8");
|
||||
};
|
||||
if path.contains('\n') {
|
||||
panic!("cannot emit rerun-if-changed: path contains newline");
|
||||
}
|
||||
emit("rerun-if-changed", path);
|
||||
}
|
||||
|
||||
/// The `rerun-if-env-changed` instruction tells Cargo to re-run the build script
|
||||
/// if the value of an environment variable of the given name has changed.
|
||||
///
|
||||
/// Note that the environment variables here are intended for global environment
|
||||
/// variables like `CC` and such, it is not possible to use this for environment
|
||||
/// variables like `TARGET` that [Cargo sets for build scripts][build-env]. The
|
||||
/// environment variables in use are those received by cargo invocations, not
|
||||
/// those received by the executable of the build script.
|
||||
///
|
||||
/// [build-env]: https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts
|
||||
#[track_caller]
|
||||
pub fn rerun_if_env_changed(key: impl AsRef<OsStr>) {
|
||||
let Some(key) = key.as_ref().to_str() else {
|
||||
panic!("cannot emit rerun-if-env-changed: key is not UTF-8");
|
||||
};
|
||||
if key.contains('\n') {
|
||||
panic!("cannot emit rerun-if-env-changed: key contains newline");
|
||||
}
|
||||
emit("rerun-if-env-changed", key);
|
||||
}
|
||||
|
||||
/// The `rustc-link-arg` instruction tells Cargo to pass the
|
||||
/// [`-C link-arg=FLAG` option][link-arg] to the compiler, but only when building
|
||||
/// supported targets (benchmarks, binaries, cdylib crates, examples, and tests).
|
||||
/// Its usage is highly platform specific. It is useful to set the shared library
|
||||
/// version or linker script.
|
||||
///
|
||||
/// [link-arg]: https://doc.rust-lang.org/rustc/codegen-options/index.html#link-arg
|
||||
#[track_caller]
|
||||
pub fn rustc_link_arg(flag: &str) {
|
||||
if flag.contains([' ', '\n']) {
|
||||
panic!("cannot emit rustc-link-arg: invalid flag {flag:?}");
|
||||
}
|
||||
emit("rustc-link-arg", flag);
|
||||
}
|
||||
|
||||
/// The `rustc-link-arg-bin` instruction tells Cargo to pass the
|
||||
/// [`-C link-arg=FLAG` option][link-arg] to the compiler, but only when building
|
||||
/// the binary target with name `BIN`. Its usage is highly platform specific. It
|
||||
/// is useful to set a linker script or other linker options.
|
||||
///
|
||||
/// [link-arg]: https://doc.rust-lang.org/rustc/codegen-options/index.html#link-arg
|
||||
#[track_caller]
|
||||
pub fn rustc_link_arg_bin(bin: &str, flag: &str) {
|
||||
if !is_ident(bin) {
|
||||
panic!("cannot emit rustc-link-arg-bin: invalid bin name {bin:?}");
|
||||
}
|
||||
if flag.contains([' ', '\n']) {
|
||||
panic!("cannot emit rustc-link-arg-bin: invalid flag {flag:?}");
|
||||
}
|
||||
emit("rustc-link-arg-bin", format_args!("{}={}", bin, flag));
|
||||
}
|
||||
|
||||
/// The `rustc-link-arg-bins` instruction tells Cargo to pass the
|
||||
/// [`-C link-arg=FLAG` option][link-arg] to the compiler, but only when building
|
||||
/// the binary target. Its usage is highly platform specific. It is useful to set
|
||||
/// a linker script or other linker options.
|
||||
///
|
||||
/// [link-arg]: https://doc.rust-lang.org/rustc/codegen-options/index.html#link-arg
|
||||
#[track_caller]
|
||||
pub fn rustc_link_arg_bins(flag: &str) {
|
||||
if flag.contains([' ', '\n']) {
|
||||
panic!("cannot emit rustc-link-arg-bins: invalid flag {flag:?}");
|
||||
}
|
||||
emit("rustc-link-arg-bins", flag);
|
||||
}
|
||||
|
||||
/// The `rustc-link-arg-tests` instruction tells Cargo to pass the
|
||||
/// [`-C link-arg=FLAG` option][link-arg] to the compiler, but only when building
|
||||
/// a tests target.
|
||||
#[track_caller]
|
||||
pub fn rustc_link_arg_tests(flag: &str) {
|
||||
if flag.contains([' ', '\n']) {
|
||||
panic!("cannot emit rustc-link-arg-tests: invalid flag {flag:?}");
|
||||
}
|
||||
emit("rustc-link-arg-tests", flag);
|
||||
}
|
||||
|
||||
/// The `rustc-link-arg-examples` instruction tells Cargo to pass the
|
||||
/// [`-C link-arg=FLAG` option][link-arg] to the compiler, but only when building
|
||||
/// an examples target.
|
||||
#[track_caller]
|
||||
pub fn rustc_link_arg_examples(flag: &str) {
|
||||
if flag.contains([' ', '\n']) {
|
||||
panic!("cannot emit rustc-link-arg-examples: invalid flag {flag:?}");
|
||||
}
|
||||
emit("rustc-link-arg-examples", flag);
|
||||
}
|
||||
|
||||
/// The `rustc-link-arg-benches` instruction tells Cargo to pass the
|
||||
/// [`-C link-arg=FLAG` option][link-arg] to the compiler, but only when building
|
||||
/// a benchmark target.
|
||||
#[track_caller]
|
||||
pub fn rustc_link_arg_benches(flag: &str) {
|
||||
if flag.contains([' ', '\n']) {
|
||||
panic!("cannot emit rustc-link-arg-benches: invalid flag {flag:?}");
|
||||
}
|
||||
emit("rustc-link-arg-benches", flag);
|
||||
}
|
||||
|
||||
/// The `rustc-link-lib` instruction tells Cargo to link the given library using
|
||||
/// the compiler’s [`-l` flag][-l]. This is typically used to link a native library
|
||||
/// using [FFI].
|
||||
///
|
||||
/// The `LIB` string is passed directly to rustc, so it supports any syntax that
|
||||
/// `-l` does. Currently the full supported syntax for `LIB` is
|
||||
/// `[KIND[:MODIFIERS]=]NAME[:RENAME]`.
|
||||
///
|
||||
/// The `-l` flag is only passed to the library target of the package, unless there
|
||||
/// is no library target, in which case it is passed to all targets. This is done
|
||||
/// because all other targets have an implicit dependency on the library target,
|
||||
/// and the given library to link should only be included once. This means that
|
||||
/// if a package has both a library and a binary target, the library has access
|
||||
/// to the symbols from the given lib, and the binary should access them through
|
||||
/// the library target’s public API.
|
||||
///
|
||||
/// The optional `KIND` may be one of dylib, static, or framework. See the
|
||||
/// [rustc book][-l] for more detail.
|
||||
///
|
||||
/// [-l]: https://doc.rust-lang.org/stable/rustc/command-line-arguments.html#option-l-link-lib
|
||||
/// [FFI]: https://doc.rust-lang.org/stable/nomicon/ffi.html
|
||||
#[track_caller]
|
||||
pub fn rustc_link_lib(lib: &str) {
|
||||
if lib.contains([' ', '\n']) {
|
||||
panic!("cannot emit rustc-link-lib: invalid lib {lib:?}");
|
||||
}
|
||||
emit("rustc-link-lib", lib);
|
||||
}
|
||||
|
||||
/// Like [`rustc_link_lib`], but with `KIND[:MODIFIERS]` specified separately.
|
||||
#[track_caller]
|
||||
pub fn rustc_link_lib_kind(kind: &str, lib: &str) {
|
||||
if kind.contains(['=', ' ', '\n']) {
|
||||
panic!("cannot emit rustc-link-lib: invalid kind {kind:?}");
|
||||
}
|
||||
if lib.contains([' ', '\n']) {
|
||||
panic!("cannot emit rustc-link-lib: invalid lib {lib:?}");
|
||||
}
|
||||
emit("rustc-link-lib", format_args!("{kind}={lib}"));
|
||||
}
|
||||
|
||||
/// The `rustc-link-search` instruction tells Cargo to pass the [`-L` flag] to the
|
||||
/// compiler to add a directory to the library search path.
|
||||
///
|
||||
/// The optional `KIND` may be one of `dependency`, `crate`, `native`, `framework`,
|
||||
/// or `all`. See the [rustc book][-L] for more detail.
|
||||
///
|
||||
/// These paths are also added to the
|
||||
/// [dynamic library search path environment variable][search-path] if they are
|
||||
/// within the `OUT_DIR`. Depending on this behavior is discouraged since this
|
||||
/// makes it difficult to use the resulting binary. In general, it is best to
|
||||
/// avoid creating dynamic libraries in a build script (using existing system
|
||||
/// libraries is fine).
|
||||
///
|
||||
/// [-L]: https://doc.rust-lang.org/stable/rustc/command-line-arguments.html#option-l-search-path
|
||||
/// [search-path]: https://doc.rust-lang.org/stable/cargo/reference/environment-variables.html#dynamic-library-paths
|
||||
#[track_caller]
|
||||
pub fn rustc_link_search(path: impl AsRef<Path>) {
|
||||
let Some(path) = path.as_ref().to_str() else {
|
||||
panic!("cannot emit rustc-link-search: path is not UTF-8");
|
||||
};
|
||||
if path.contains('\n') {
|
||||
panic!("cannot emit rustc-link-search: path contains newline");
|
||||
}
|
||||
emit("rustc-link-search", path);
|
||||
}
|
||||
|
||||
/// Like [`rustc_link_search`], but with KIND specified separately.
|
||||
#[track_caller]
|
||||
pub fn rustc_link_search_kind(kind: &str, path: impl AsRef<Path>) {
|
||||
if kind.contains(['=', '\n']) {
|
||||
panic!("cannot emit rustc-link-search: invalid kind {kind:?}");
|
||||
}
|
||||
let Some(path) = path.as_ref().to_str() else {
|
||||
panic!("cannot emit rustc-link-search: path is not UTF-8");
|
||||
};
|
||||
if path.contains('\n') {
|
||||
panic!("cannot emit rustc-link-search: path contains newline");
|
||||
}
|
||||
emit("rustc-link-search", format_args!("{kind}={path}"));
|
||||
}
|
||||
|
||||
/// The `rustc-flags` instruction tells Cargo to pass the given space-separated
|
||||
/// flags to the compiler. This only allows the `-l` and `-L` flags, and is
|
||||
/// equivalent to using [`rustc_link_lib`] and [`rustc_link_search`].
|
||||
#[track_caller]
|
||||
pub fn rustc_flags(flags: &str) {
|
||||
if flags.contains('\n') {
|
||||
panic!("cannot emit rustc-flags: invalid flags");
|
||||
}
|
||||
emit("rustc-flags", flags);
|
||||
}
|
||||
|
||||
/// The `rustc-cfg` instruction tells Cargo to pass the given value to the
|
||||
/// [`--cfg` flag][cfg] to the compiler. This may be used for compile-time
|
||||
/// detection of features to enable conditional compilation.
|
||||
///
|
||||
/// Note that this does not affect Cargo’s dependency resolution. This cannot
|
||||
/// be used to enable an optional dependency, or enable other Cargo features.
|
||||
///
|
||||
/// Be aware that [Cargo features] use the form `feature="foo"`. `cfg` values
|
||||
/// passed with this flag are not restricted to that form, and may provide just
|
||||
/// a single identifier, or any arbitrary key/value pair. For example, emitting
|
||||
/// `rustc_cfg("abc")` will then allow code to use `#[cfg(abc)]` (note the lack
|
||||
/// of `feature=`). Or an arbitrary key/value pair may be used with an `=` symbol
|
||||
/// like `rustc_cfg(r#"my_component="foo""#)`. The key should be a Rust identifier,
|
||||
/// the value should be a string.
|
||||
///
|
||||
/// [cfg]: https://doc.rust-lang.org/rustc/command-line-arguments.html#option-cfg
|
||||
/// [Cargo features]: https://doc.rust-lang.org/cargo/reference/features.html
|
||||
#[track_caller]
|
||||
pub fn rustc_cfg(key: &str) {
|
||||
if !is_ident(key) {
|
||||
panic!("cannot emit rustc-cfg: invalid key {key:?}");
|
||||
}
|
||||
emit("rustc-cfg", key);
|
||||
}
|
||||
|
||||
/// Like [`rustc_cfg`], but with the value specified separately. To replace the
|
||||
/// less convenient `rustc_cfg(r#"my_component="foo""#)`, you can instead use
|
||||
/// `rustc_cfg_value("my_component", "foo")`.
|
||||
#[track_caller]
|
||||
pub fn rustc_cfg_value(key: &str, value: &str) {
|
||||
if !is_ident(key) {
|
||||
panic!("cannot emit rustc-cfg-value: invalid key");
|
||||
}
|
||||
let value = value.escape_default();
|
||||
emit("rustc-cfg", format_args!("{key}=\"{value}\""));
|
||||
}
|
||||
|
||||
/// Add to the list of expected config names that is used when checking the
|
||||
/// *reachable* cfg expressions with the [`unexpected_cfgs`] lint.
|
||||
///
|
||||
/// This form is for keys without an expected value, such as `cfg(name)`.
|
||||
///
|
||||
/// It is recommended to group the `rustc_check_cfg` and `rustc_cfg` calls as
|
||||
/// closely as possible in order to avoid typos, missing check_cfg, stale cfgs,
|
||||
/// and other mistakes.
|
||||
///
|
||||
/// [`unexpected_cfgs`]: https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#unexpected-cfgs
|
||||
#[doc = msrv!("1.80")]
|
||||
#[track_caller]
|
||||
pub fn rustc_check_cfgs(keys: &[&str]) {
|
||||
if keys.is_empty() {
|
||||
return;
|
||||
}
|
||||
for key in keys {
|
||||
if !is_ident(key) {
|
||||
panic!("cannot emit rustc-check-cfg: invalid key {key:?}");
|
||||
}
|
||||
}
|
||||
|
||||
if allow_use::check_cfg() {
|
||||
let mut directive = keys[0].to_string();
|
||||
for key in &keys[1..] {
|
||||
write!(directive, ", {key}").expect("writing to string should be infallible");
|
||||
}
|
||||
emit("rustc-check-cfg", format_args!("cfg({directive})"));
|
||||
}
|
||||
}
|
||||
|
||||
/// Add to the list of expected config names that is used when checking the
|
||||
/// *reachable* cfg expressions with the [`unexpected_cfgs`] lint.
|
||||
///
|
||||
/// This form is for keys with expected values, such as `cfg(name = "value")`.
|
||||
///
|
||||
/// It is recommended to group the `rustc_check_cfg` and `rustc_cfg` calls as
|
||||
/// closely as possible in order to avoid typos, missing check_cfg, stale cfgs,
|
||||
/// and other mistakes.
|
||||
///
|
||||
/// [`unexpected_cfgs`]: https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#unexpected-cfgs
|
||||
#[doc = msrv!("1.80")]
|
||||
#[track_caller]
|
||||
pub fn rustc_check_cfg_values(key: &str, values: &[&str]) {
|
||||
if !is_ident(key) {
|
||||
panic!("cannot emit rustc-check-cfg: invalid key {key:?}");
|
||||
}
|
||||
if values.is_empty() {
|
||||
rustc_check_cfgs(&[key]);
|
||||
return;
|
||||
}
|
||||
|
||||
if allow_use::check_cfg() {
|
||||
let mut directive = format!("\"{}\"", values[0].escape_default());
|
||||
for value in &values[1..] {
|
||||
write!(directive, ", \"{}\"", value.escape_default())
|
||||
.expect("writing to string should be infallible");
|
||||
}
|
||||
emit(
|
||||
"rustc-check-cfg",
|
||||
format_args!("cfg({key}, values({directive}))"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// The `rustc-env` instruction tells Cargo to set the given environment variable
|
||||
/// when compiling the package. The value can be then retrieved by the
|
||||
/// [`env!` macro][env!] in the compiled crate. This is useful for embedding
|
||||
/// additional metadata in crate’s code, such as the hash of git HEAD or the
|
||||
/// unique identifier of a continuous integration server.
|
||||
///
|
||||
/// See also the [environment variables automatically included by Cargo][cargo-env].
|
||||
///
|
||||
/// [cargo-env]: https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates
|
||||
#[track_caller]
|
||||
pub fn rustc_env(key: &str, value: &str) {
|
||||
if key.contains(['=', '\n']) {
|
||||
panic!("cannot emit rustc-env: invalid key {key:?}");
|
||||
}
|
||||
if value.contains('\n') {
|
||||
panic!("cannot emit rustc-env: invalid value {value:?}");
|
||||
}
|
||||
emit("rustc-env", format_args!("{key}={value}"));
|
||||
}
|
||||
|
||||
/// The `rustc-cdylib-link-arg` instruction tells Cargo to pass the
|
||||
/// [`-C link-arg=FLAG` option][link-arg] to the compiler, but only when building
|
||||
/// a `cdylib` library target. Its usage is highly platform specific. It is useful
|
||||
/// to set the shared library version or the runtime-path.
|
||||
///
|
||||
/// [link-arg]: https://doc.rust-lang.org/rustc/codegen-options/index.html#link-arg
|
||||
#[track_caller]
|
||||
pub fn rustc_cdylib_link_arg(flag: &str) {
|
||||
if flag.contains('\n') {
|
||||
panic!("cannot emit rustc-cdylib-link-arg: invalid flag {flag:?}");
|
||||
}
|
||||
emit("rustc-cdylib-link-arg", flag);
|
||||
}
|
||||
|
||||
/// The `warning` instruction tells Cargo to display a warning after the build
|
||||
/// script has finished running. Warnings are only shown for path dependencies
|
||||
/// (that is, those you’re working on locally), so for example warnings printed
|
||||
/// out in [crates.io] crates are not emitted by default. The `-vv` “very verbose”
|
||||
/// flag may be used to have Cargo display warnings for all crates.
|
||||
///
|
||||
/// [crates.io]: https://crates.io/
|
||||
#[track_caller]
|
||||
pub fn warning(message: &str) {
|
||||
if message.contains('\n') {
|
||||
panic!("cannot emit warning: message contains newline");
|
||||
}
|
||||
emit("warning", message);
|
||||
}
|
||||
|
||||
/// Metadata, used by `links` scripts.
|
||||
#[track_caller]
|
||||
pub fn metadata(key: &str, val: &str) {
|
||||
if !is_ascii_ident(key) {
|
||||
panic!("cannot emit metadata: invalid key {key:?}");
|
||||
}
|
||||
if val.contains('\n') {
|
||||
panic!("cannot emit metadata: invalid value {val:?}");
|
||||
}
|
||||
|
||||
if allow_use::double_colon_directives() {
|
||||
emit("metadata", format_args!("{}={}", key, val));
|
||||
} else {
|
||||
emit(key, val);
|
||||
}
|
||||
}
|
@ -184,6 +184,7 @@ fn bump_check(args: &clap::ArgMatches, gctx: &cargo::util::GlobalContext) -> Car
|
||||
let mut cmd = ProcessBuilder::new("cargo");
|
||||
cmd.arg("semver-checks")
|
||||
.arg("--workspace")
|
||||
.args(&["--exclude", "build-rs"]) // FIXME: Remove once 1.84 is stable.
|
||||
.arg("--baseline-rev")
|
||||
.arg(referenced_commit.id().to_string());
|
||||
for krate in crates_not_check_against_channels {
|
||||
|
@ -170,6 +170,7 @@ The degree of process is correlated with the degree of change being proposed:
|
||||
|
||||
Per the [Rust crate ownership policy](https://forge.rust-lang.org/policies/crate-ownership.html), the Cargo team's "Intentional Artifacts" include:
|
||||
|
||||
- [build-rs](https://crates.io/crates/build-rs)
|
||||
- [cargo-credential](https://crates.io/crates/cargo-credential)
|
||||
- [cargo-platform](https://crates.io/crates/cargo-platform)
|
||||
- [cargo-util-schemas](https://crates.io/crates/cargo-util-schemas)
|
||||
|
Loading…
x
Reference in New Issue
Block a user