๐ŸŽ“ A1Learner
๐Ÿ”

Rust Build Scripts

A build script is a small Rust program that Cargo runs before building a package. A build script can stamp a version into the code, or generate a table too big to type.

The script is a small Rust program

It lives in build.rs, in the project root โ€” or name a different file with build = "path" in the [package] section. Cargo compiles it and runs it before building anything else in your package.

// build.rs
fn main() {
    println!("cargo:rustc-env=APP_VERSION=1.4.0");
}

Your code reads the stamped value

env! picks the value up while your code compiles:

fn main() {
    println!("version = {}", env!("APP_VERSION"));
}

Say which files the script reads

With a rerun line, Cargo re-runs the script only when one of those files changes. Without one, any change in the package re-runs it โ€” safe, but slower than needed.

println!("cargo:rerun-if-changed=version.txt");

Generated code goes in OUT_DIR

The script writes generated files into the OUT_DIR folder. Your code pulls one in with include!:

include!(concat!(env!("OUT_DIR"), "/generated.rs"));

Turn on your own cfg

A rustc-cfg line switches on a condition of your own for this build โ€” the Conditional Compilation lesson uses such conditions.

println!("cargo:rustc-cfg=fast_math");

Example

// build.rs
// fn main() {
//     println!("cargo:rustc-env=APP_VERSION=1.4.0");
// }
// src/main.rs then reads the value with env!("APP_VERSION")
fn main() {
    println!("1. Cargo runs build.rs first");
    println!("2. the script prints: cargo:rustc-env=APP_VERSION=1.4.0");
    println!("3. main.rs then prints: version = 1.4.0");
}

Key points

  • Cargo compiles build.rs.
  • It runs the script before building anything else in your package.
  • If the script fails, the whole build fails.
  • The script talks back by printing lines that start with cargo:.
  • Cargo reads those lines as instructions.
  • Any other printing is saved to a file under target/.
  • It is not shown on your screen.
  • Crates the script itself needs go under [build-dependencies].
  • The script runs on the machine doing the build.
  • So its libraries stay separate from the libraries of your program.

In this example, the comments show the whole mechanism in two small files. The build script prints one cargo: line, which sets the value APP_VERSION to 1.4.0 for this build. The main program reads that value while it compiles, with env!("APP_VERSION"), and prints it. The runnable code traces the three steps in order. The script runs first. The cargo: line carries the value across. The program prints version = 1.4.0.

Note

A build script can only give instructions for its own package.

It is a normal Rust program.

But it runs at build time.

It is not part of the program you ship.

Try it Yourself

Edit the code, then press Run.

Running is simulated ยท Rust Playground

Exercise

How does a build script pass a value into the code Cargo is about to compile?