architect 0.0.0

A cargo interface for build scripts
Documentation
//! <https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script>
//!
//! Build scripts communicate with Cargo by printing to stdout. Cargo will
//! interpret each line that starts with `cargo::` as an instruction that will
//! influence compilation of the package. All other lines are ignored.
//!
//! > The order of `cargo::` instructions printed by the build script may affect
//! > the order of arguments that `cargo` passes to `rustc`. In turn, the order
//! > of arguments passed to `rustc` may affect the order of arguments passed to
//! > the linker. Therefore, you will want to pay attention to the order of the
//! > build script’s instructions. For example, if object `foo` needs to link
//! > against library `bar`, you may want to make sure that library `bar`’s
//! > [`cargo::rustc-link-lib`] instruction appears _after_ instructions to link
//! > object `foo`.

/// The `rustc-link-arg` instruction tells Cargo to pass the [`-C link-arg=FLAG`
/// option] 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.
///
/// [`cargo::rustc-link-lib`]: https://doc.rust-lang.org/cargo/reference/build-scripts.html#rustc-link-lib
/// [`-C link-arg=FLAG` option]: https://doc.rust-lang.org/rustc/codegen-options/index.html#link-arg
pub fn rustc_link_arg(flag: &str) {
	println!("cargo::rustc-link-arg={flag}");
}

/// The `rustc-link-arg-bin` instruction tells Cargo to pass the [`-C
/// link-arg=FLAG` option] 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.
///
/// [`-C link-arg=FLAG` option]: https://doc.rust-lang.org/rustc/codegen-options/index.html#link-arg
pub fn rustc_link_arg_bin(bin: &str, flag: &str) {
	println!("cargo::rustc-link-arg-bin={bin}={flag}");
}

/// The `rustc-link-arg-bins` instruction tells Cargo to pass the [`-C
/// link-arg=FLAG` option] to the compiler, but only when building a binary
/// target. Its usage is highly platform specific. It is useful to set a linker
/// script or other linker options.
///
/// [`-C link-arg=FLAG` option]: https://doc.rust-lang.org/rustc/codegen-options/index.html#link-arg
pub fn rustc_link_arg_bins(flag: &str) {
	println!("cargo::rustc-link-arg-bins={flag}");
}

/// The `rustc-link-lib` instruction tells Cargo to link the given library using
/// the compiler’s [`-l` flag]. 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 fully 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] for more detail.
///
/// [`-l` flag]: https://doc.rust-lang.org/rustc/command-line-arguments.html#option-l-link-lib
/// [FFI]: https://doc.rust-lang.org/nomicon/ffi.html
/// [rustc book]: https://doc.rust-lang.org/rustc/command-line-arguments.html#option-l-link-lib
pub fn rustc_link_lib(lib: &str) {
	println!("cargo::rustc-link-lib={lib}")
}

/// The `rustc-link-arg-tests` instruction tells Cargo to pass the [`-C
/// link-arg=FLAG` option] to the compiler, but only when building a tests
/// target.
///
/// [`-C link-arg=FLAG` option]: https://doc.rust-lang.org/rustc/codegen-options/index.html#link-arg
pub fn rustc_link_arg_tests(flag: &str) {
	println!("cargo::rustc-link-arg-tests={flag}")
}

/// The `rustc-link-arg-examples` instruction tells Cargo to pass the [`-C
/// link-arg=FLAG` option] to the compiler, but only when building an examples
/// target.
///
/// [`-C link-arg=FLAG` option]: https://doc.rust-lang.org/rustc/codegen-options/index.html#link-arg
pub fn rustc_link_arg_examples(flag: &str) {
	println!("cargo::rustc-link-arg-examples={flag}")
}

/// The `rustc-link-arg-benches` instruction tells Cargo to pass the [`-C
/// link-arg=FLAG` option] to the compiler, but only when building a benchmark
/// target.
///
/// [`-C link-arg=FLAG` option]: https://doc.rust-lang.org/rustc/codegen-options/index.html#link-arg
pub fn rustc_link_arg_benches(flag: &str) {
	println!("cargo::rustc-link-arg-benches={flag}")
}

/// 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] for more detail.
///
/// These paths are also added to the [dynamic library search path environment
/// variable] 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` flag]: https://doc.rust-lang.org/rustc/command-line-arguments.html#option-l-search-path
/// [rustc book]: https://doc.rust-lang.org/rustc/command-line-arguments.html#option-l-search-path
/// [dynamic library search path environment variable]: https://doc.rust-lang.org/cargo/reference/environment-variables.html#dynamic-library-paths
pub fn rustc_link_search(kind: Option<&str>, path: &str) {
	if let Some(kind) = kind {
		println!("cargo::rustc-link-search={kind}={path}")
	} else {
		println!("cargo::rustc-link-search={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`].
///
/// [`rustc-link-lib`]: https://doc.rust-lang.org/cargo/reference/build-scripts.html#rustc-link-lib
/// [`rustc-link-search`]: https://doc.rust-lang.org/cargo/reference/build-scripts.html#rustc-link-search
pub fn rustc_flags(flags: &[&str]) {
	println!("cargo::rustc-flags={}", flags.join(" "))
}

/// The `rustc-cfg` instruction tells Cargo to pass the given value to the
/// [`--cfg` flag] to the compiler. This may be used for compile-time detection
/// of features to enable [conditional compilation]. Custom cfgs must either be
/// expected using the [`cargo::rustc-check-cfg`] instruction or usage will need
/// to allow the [`unexpected_cfgs`] lint to avoid unexpected cfgs warnings.
///
/// 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
/// `cargo::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 `cargo::rustc-cfg=my_component="foo"`. The key should be a Rust
/// identifier, the value should be a string.
///
/// [`--cfg` flag]: https://doc.rust-lang.org/rustc/command-line-arguments.html#option-cfg
/// [conditional compilation]: https://doc.rust-lang.org/reference/conditional-compilation.html
/// [`cargo::rustc-check-cfg`]: https://doc.rust-lang.org/cargo/reference/build-scripts.html#rustc-check-cfg
/// [`unexpected_cfgs`]: https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#unexpected-cfgs
/// [`Cargo features`]: https://doc.rust-lang.org/cargo/reference/features.html
pub fn rustc_cfg(key: &str, value: Option<&str>) {
	if let Some(value) = value {
		println!("cargo::rustc-cfg={key}=\"{value}\"")
	} else {
		println!("cargo::rustc-cfg={key}")
	}
}

/// Add to the list of expected config names and values that is used when
/// checking the reachable cfg expressions with the [`unexpected_cfgs`] lint.
///
/// The syntax of CHECK_CFG mirrors the rustc [`--check-cfg` flag], see
/// [Checking conditional configurations] for more details.
///
/// The instruction can be used like this:
///
///     // build.rs
///     println!("cargo::rustc-check-cfg=cfg(foo, values(\"bar\"))");
///     if foo_bar_condition {
///         println!("cargo::rustc-cfg=foo=\"bar\"");
///     }
///
/// Note that all possible cfgs should be defined, regardless of which cfgs are
/// currently enabled. This includes all possible values of a given cfg name.
///
/// It is recommended to group the `cargo::rustc-check-cfg` and
/// [`cargo::rustc-cfg`] instructions as closely as possible in order to avoid
/// typos, missing check-cfg, stale cfgs…
///
/// See also the [conditional compilation] example.
///
/// [`unexpected_cfgs`]: https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#unexpected-cfgs
/// [`--check-cfg` flag]: https://doc.rust-lang.org/rustc/command-line-arguments.html#option-check-cfg
/// [Checking conditional configurations]: https://doc.rust-lang.org/rustc/check-cfg.html
/// [`cargo::rustc-cfg`]: https://doc.rust-lang.org/rustc/command-line-arguments.html#option-cfg
/// [conditional compilation]: https://doc.rust-lang.org/cargo/reference/build-script-examples.html#conditional-compilation
pub fn rustc_check_cfg(check_cfg: &str) {
	println!("cargo::rustc-check-cfg={check_cfg}")
}

/// 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] 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].
///
/// > Note: These environment variables are also set when running an executable
/// > with `cargo run` or `cargo test`. However, this usage is discouraged since
/// > it ties the executable to Cargo’s execution environment. Normally, these
/// > environment variables should only be checked at compile-time with the
/// > `env!` macro.
///
/// [`env!` macro]: https://doc.rust-lang.org/std/macro.env.html
/// [environment variables automatically included by Cargo]: https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates
pub fn rustc_env(var: &str, value: &str) {
	println!("cargo::rustc-env={var}={value}")
}

/// The `rustc-cdylib-link-arg` instruction tells Cargo to pass the [`-C
/// link-arg=FLAG` option] 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.
///
/// [`-C link-arg=FLAG` option]: https://doc.rust-lang.org/rustc/codegen-options/index.html#link-arg
pub fn rustc_cdylib_link_arg(flag: &str) {
	println!("cargo::rustc-cdylib-link-arg={flag}")
}

/// The `error` instruction tells Cargo to display an error after the build
/// script has finished running, and then fail the build.
///
/// > Note: Build script libraries should carefully consider if they want to use
/// > `cargo::error` versus returning a `Result`. It may be better to return a
/// > `Result`, and allow the caller to decide if the error is fatal or not. The
/// > caller can then decide whether or not to display the `Err` variant using
/// > `cargo::error`.
pub fn error(message: &str) {
	println!("cargo::error={message}")
}

/// 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, unless the build
/// fails. The `-vv` “very verbose” flag may be used to have Cargo display
/// warnings for all crates.
///
/// [crates.io]: https://crates.io/
pub fn warning(message: &str) {
	println!("cargo::warning={message}")
}

/// 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 emitting `cargo::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.
pub fn rerun_if_changed(path: &str) {
	println!("cargo::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]. The environment
/// variables in use are those received by `cargo` invocations, not those
/// received by the executable of the build script.
///
/// [Cargo sets for build scripts]: https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts
pub fn rerun_if_env_changed(name: &str) {
	println!("cargo::rerun-if-env-changed={name}")
}

/// Build scripts can generate an arbitrary set of metadata in the form of
/// key-value pairs. This metadata is set with the `cargo::metadata=KEY=VALUE`
/// instruction.
///
/// The metadata is passed to the build scripts of *dependent* packages. For
/// example, if the package `foo` depends on `bar`, which links `baz`, then if
/// `bar` generates `key=value` as part of its build script metadata, then the
/// build script of `foo` will have the environment variables
/// `DEP_BAZ_KEY=value` (note that the value of the `links` key is used). See
/// the [“Using another `sys` crate”] for an example of how this can be used.
///
/// Note that metadata is only passed to immediate dependents, not transitive
/// dependents.
///
/// [“Using another `sys` crate”]: https://doc.rust-lang.org/cargo/reference/build-script-examples.html#using-another-sys-crate
pub fn metadata(key: &str, value: &str) {
	println!("cargo::metadata={key}={value}")
}