'How can I force `build.rs` to run again without cleaning my whole project?

How can I force build.rs to run again without cleaning my whole project? I checked cargo build --help but I couldn't find anything related to build.rs.



Solution 1:[1]

Register build.rs as a crate's bin target:

  1. Add this to your Cargo.toml file:
[package]
edition = "2018"
build = "build.rs"

[[bin]]
name = "force-build"
path = "build.rs"
required-features = ["build_deps"]  # only needed for build-dependencies
  1. If you have any [build-dependencies] (e.g. some_crate = "1.2.3"), you need to add those to (the main) [dependencies] (sadly no [bin-dependencies] as of yet), but you can make them optional:
[dependencies]
some_crate = { version = "1.2.3", optional = true }

[features]
build_deps = ["some_crate"]

Then you can run the build script with:

$ cargo run --bin force-build --features build_deps

(or $ cargo run --bin force-build when no [build-dependencies])

  • You can even disable the automatic call of the build script by replacing the build = "build.rs" line in Cargo.toml with build = false

  • Note: since the OUT_DIR env var is not present for bin targets, if your build.rs script uses env!("OUT_DIR"), you may "fix this" by using concat!(env!("CARGO_MANIFEST_DIR"), "/target/") instead.

Solution 2:[2]

If build.rs changes, Cargo already rebuilds the project:

Note that if the build script itself (or one of its dependencies) changes, then it's rebuilt and rerun unconditionally, so cargo:rerun-if-changed=build.rs is almost always redundant (unless you want to ignore changes in all other files except for build.rs). doc

On Linux, I will just do touch build.rs && cargo build. For Windows, see Windows equivalent of the Linux command 'touch'?

Solution 3:[3]

If you got target under gitignore (which you should) this might be useful for any file changes when you're developing and testing the build script.

if Path::new(".git/HEAD").exists() {
    println!("cargo:rerun-if-changed=.git/HEAD");
}

Solution 4:[4]

if you're trying to rebuild based on non-rust or include!() files that might've changed, you can use

const _: &[u8] = include_bytes!("foobar.baz");

to ensure that any changes to those files will trigger a new build. pretty sure this solution adds neither time nor filesize.

you can shove this into a macro too, so its easy to do a bunch of files.

macro_rules! build_on{($file:literal) => {
    const _: &[u8] = include_bytes!($file);
}

build_on!("foobar.baz");

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Caesar
Solution 2 Shepmaster
Solution 3 Seivan
Solution 4