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
.
6 Answers
If you print
"cargo:rerun-if-changed=<FILE>"
the build will be triggered every time the file has changed.
rerun-if-changed=PATH
is a path to a file or directory which indicates that the build script should be re-run if it changes (detected by a more-recent last-modified timestamp on the file). Normally build scripts are re-run if any file inside the crate root changes, but this can be used to scope changes to just a small set of files. -- source
I'm not aware of a solution without changing a file manually (I just put a whitespace anywhere in my build.rs
, it will be removed by rustfmt
though).
I have several buildscripts in my projects, and mostly these two lines give me a nice solution:
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=path/to/Cargo.lock");
but I guess you are looking for a command rustc
/cargo
command. Anyway, you can put in a small script, which will edit a certain file, which will trigger the build-process.

- 7,755
- 11
- 41
- 69
-
2I don't understand "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)." this is not needed – Stargateur Apr 05 '19 at 13:10
-
1It should not be needed, however, I noticed that sometimes it does not work (maybe this was a bug, which has been solved now?). – Tim Diekmann Apr 05 '19 at 13:44
Register build.rs
as a crate's bin
target:
- 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
- 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 inCargo.toml
withbuild = false
Note: since the
OUT_DIR
env var is not present forbin
targets, if yourbuild.rs
script usesenv!("OUT_DIR")
, you may "fix this" by usingconcat!(env!("CARGO_MANIFEST_DIR"), "/target/")
instead.

- 6,733
- 4
- 38
- 44

- 1,439
- 8
- 12
-
3
-
this works but i'm getting a warning "warning: file `.../build.rs` found to be present in multiple build targets". any idea how to avoid it? – Markus Unterwaditzer Mar 29 '23 at 17:41
-
@MarkusUnterwaditzer Yeah, this is exactly what this solution intends to do, but it's not really how Cargo would expect it, I guess, hence the warning. Another approach could be to create a `src/bin/force_build.rs` file, with `include!("../../build.rs");` as its body. The advantage of this other approach is that you won't even need to touch the `Cargo.toml` file unless you needed the `build_deps` features shenanigans – Daniel H-M Mar 30 '23 at 19:54
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 forbuild.rs
). doc
On Linux, I will just do touch build.rs && cargo build
. For Windows, see Windows equivalent of the Linux command 'touch'?

- 388,571
- 95
- 1,107
- 1,366

- 24,473
- 8
- 65
- 91
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");
}

- 668
- 6
- 13
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");

- 111
- 1
- 2
I'm currently on stable rust 1.70.0
, and what I accidentally realized is that if you use a non-existent file path with cargo:rerun-if-changed
, it will always trigger the build script.
So simply add it to the top of your build script like this:
// build.rs
fn main() {
println!("cargo:rerun-if-changed=NULL");
// do your build stuff here...
}
I'm not sure if this creates any side effects or other unintended issues. So far, it works perfectly fine for me. Remember, this could easily change in the future and your build scripts could fail without you even knowing.

- 773
- 9
- 23