diff --git a/src/doc/src/reference/build-script-examples.md b/src/doc/src/reference/build-script-examples.md index 567870c5c6c..5cd6578fb3e 100644 --- a/src/doc/src/reference/build-script-examples.md +++ b/src/doc/src/reference/build-script-examples.md @@ -430,6 +430,36 @@ already installed. // … rest of code that makes use of zlib. ``` +## Reading target configuration + +When a build script needs to make decisions based on the target platform, it should read the `CARGO_CFG_*` environment +variables rather than using `cfg!` or `#[cfg]` attributes. This is because +the build script is compiled for and runs on the *host* machine, while +`CARGO_CFG_*` variables reflect the *target* platform, an important distinction +when cross-compiling. +```rust,ignore +// build.rs + +fn main() { + // reads the TARGET configuration + let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap(); + + if target_os == "windows" { + println!("cargo::rustc-link-lib=userenv"); + } else if target_os == "linux" { + println!("cargo::rustc-link-lib=pthread"); + } +} +``` + +Note that some configuration values may contain multiple values separated by +commas (for example, `CARGO_CFG_TARGET_FAMILY` may be `unix,wasm`). When +checking these values, be sure to handle this appropriately. + +For a more convenient, typed API, consider using the [`build-rs`] crate +which handles these details for you. + +[`build-rs`]: https://crates.io/crates/build-rs ## Conditional compilation diff --git a/src/doc/src/reference/build-scripts.md b/src/doc/src/reference/build-scripts.md index 71509ba3af8..d78efb40b38 100644 --- a/src/doc/src/reference/build-scripts.md +++ b/src/doc/src/reference/build-scripts.md @@ -67,6 +67,19 @@ the source directory of the build script’s package. [build-env]: environment-variables.md#environment-variables-cargo-sets-for-build-scripts +> **Note:** When checking [configuration options] like `target_os` or `target_arch` +> in a build script, do not use the `cfg!` macro or `#[cfg]` attribute, these +> check the **host** machine (where the build script runs), not the **target** +> platform you're compiling for. This distinction matters when cross-compiling. +> +> Instead, read the corresponding [`CARGO_CFG_*`][build-env] environment variables, +> which correctly reflect the target's configuration. For a typed API, consider +> using the [`build-rs`] crate. See the [build script examples] for more details. + +[configuration options]: ../../reference/conditional-compilation.html +[`build-rs`]: https://crates.io/crates/build-rs +[build script examples]: build-script-examples.md#conditional-compilation + ## Outputs of the Build Script Build scripts may save any output files or intermediate artifacts in the diff --git a/src/doc/src/reference/environment-variables.md b/src/doc/src/reference/environment-variables.md index e2da513d490..df1b180a097 100644 --- a/src/doc/src/reference/environment-variables.md +++ b/src/doc/src/reference/environment-variables.md @@ -365,6 +365,11 @@ let out_dir = env::var("OUT_DIR").unwrap(); > hence variables present in one target triple might not be available in the other. > > Some cfg values like `test` are not available. + > + > **Tip:** For a typed API to read these values, consider using the [`build-rs`] + > crate instead of parsing environment variables manually. Also note that + > `CARGO_CFG_*` variables should be used instead of the `cfg!` macro or `#[cfg]` + > attribute in build scripts, those check the *host* platform, not the *target*. * `OUT_DIR` --- 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. Cargo does not clean or reset this @@ -429,6 +434,7 @@ let out_dir = env::var("OUT_DIR").unwrap(); [`release`]: profiles.md#release [`debug`]: profiles.md#debug [`opt-level`]: profiles.md#opt-level +[`build-rs`]: https://crates.io/crates/build-rs ## Environment variables Cargo sets for `cargo test`