Performing any platform specific configuration needed for the crate
Lifecycle of a Build Script
Just before a package is build, Cargo will compile a build script into an executable (if it has not already been built).
It will then run the script, which may perform any number of tasks.
The script may communicate with Cargo by printing specially formatted commands prefixed with cargo:: to stdout.
The build script will be rebuilt if any of its source files or dependencies change.
By default, Cargo will re-run the build script if any of the files in the package changes.
Typically, it is best to use rerun-if commands, described later in the change section below. to narrow the focus of what triggers a build script to run again.
Once the build script successfully finishes executing, the rest of the package will be compiled.
Inputs to the Build Script
When the build script is run, there are number of inputs to the build script, all passed in the form of environment variables.
In addition, to environment variables, the build script's current directory is the source directory of the build script's package.
Outputs of the Build Script
Build scripts may save any output files or intermediate artifacts in the directory specified in the OUT_DIR environment variable.
Scripts should not modify any files outside of that directory.
Build scripts communicate with Cargo by printing to stdout.
Cargo will interpet each line that starts with cargo:: as a special command.
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 output of the script is hidden from the terminal during normal compilation.
If you would like to see the output directly in your terminal, invoke Cargo as very verbose with the -vv flag.
This only happens when the build script is run.
If Cargo determines nothing has changed, it will not re-run the script.
All the lines printed to stdout by a build script are writte to a file like target/debug/build/<pkg>/output.
The stderr output is also saved in the same directory.
The following is a summary of the instructiosn that Cargo recognizes, with each one detailed below.
cargo::rerun-if-changed=PATH - Tells cargo when to re-run the build script
cargo::rerun-if-env-changed=VAR - Tells cargo when to re-run the build script
cargo::rustc-link-arg=FLAG - Passes custom flags to a linker for benchmarks, binaries, cdylilb crates, examples, and tests
cargo::rustc-link-arg-bin=BIN=FLAG - Passes custom flags to a linker for the binary BIN
cargo::rustc-link-arg-tests=FLAG - Passes custom flags to a linker for tests
cargo::rustc-link-arg-examples=FLAG - Passes custom flags to a linker for examples.
cargo::rustc-link-arg-benches=FLAG - Passes custom flags to a linker for benchmarks.
cargo::rustc-link-lib=LIB - Adds a library to link.
cargo::rustc-link-search=[KIND=]PATH - Adds to the library search path.
cargo::rustc-flags=FLAGS - Passes certain flags to the compiler.
cargo::rustc-check-cfg=CHECK_CFG - Register custom cfgs as expected for compile-time checking of configs.
cargo::rustc-env=VAR=VALUE - Sets an environment variable.
cargo::rustc-cdylib-link-arg=FLAG - Passes custom flags to a linker for cdylib crates.
cargo::error=MESSAGE - Displays an error on the terminal.
cargo::warning=MESSAGE - Displays a warning on the terminal.
cargo::metadata=KEY=VALUE - Metadata, used by links scripts.
Build Dependencies
Build scripts are also allowed to have dependencies on other Cargo-based crates.
Dependencies are declared through the [build-dependencies] section in the Cargo.toml file.
The build script does not have access to the dependencies listed in the dependencies section or dev-dependencies section.
Also build dependencies are not available to the package itself unless explicitly added in the dependencies section.
It is recommended to carefully consider each dependency you add, weighing against the impact on compile time, licensing, maintenance, etc.
Cargo will attempt to reused dependency if it is shared between build dependencies and normal dependencies.
However, this is not always possible, for example, when cross-compiling, so keep that in consideration of the impact on compile time.
Change Detection
When rebuilding a package, Cargo does not necessarily know if the build script needs to run again.
By default, it takes conservative approach of always re-running the build script if any file within the package is changed.
For most cases, this is not good choice, so it is recommended that every build script emit at least one of the rerun-if instructions.
If these are emitted, then Cargo will only re-run the script if the given value has changed.
The links Manifest Key
The package.links key may be set in the Cargo.toml manifest to declare that the package links with the given native library.
The purpose of this manifest key is to give Cargo an understanding about the set of native dependencies that a package has, as well as providing a principled system of passing metadata between package build scripts.
[package]links="foo"
This manifest states that the package links to the libfoo native library.
When using the links key, the package must have a build script, and the build script should use the rustc-link-lib instruction to link the library.
Primarily, Cargo requires that there is at most one package per links value.
In other words, it is forbidden to have two packages link to the same native library.
This prevents duplicate symbols between crates.
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 script 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 build script of foo will have the environment variables DEP_BAZ_KEY=value.