如何在不清理整个项目的情况下强制build.rs
再次运行?我查看了cargo build --help
,但找不到与build.rs
相关的任何内容。
答案 0 :(得分:6)
如果您打印
"cargo:rerun-if-changed=<FILE>"
每次文件更改时都会触发构建。
rerun-if-changed=PATH
是文件或目录的路径,表示如果构建脚本发生更改(应该通过文件中更新的最后修改时间戳检测到),则应重新运行构建脚本。通常,如果crate根目录中的任何文件发生更改,则会重新运行构建脚本,但这可以用于将更改范围仅限于一小组文件。 - source
我不知道没有手动更改文件的解决方案(我只是在我的build.rs
中放置了一个空格,但rustfmt
将删除它。)
我的项目中有几个构建脚本,大多数这两行给了我一个很好的解决方案:
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=path/to/Cargo.lock");
但我想您正在寻找命令rustc
/ cargo
命令。无论如何,你可以放入一个小脚本,它将编辑某个文件,这将触发构建过程。
答案 1 :(得分:2)
build.rs
注册为板条箱的bin
目标:将此添加到您的Cargo.toml
文件中:
[package]
edition = "2018"
build = "build.rs"
[[bin]]
name = "force-build"
path = "build.rs"
required-features = ["build_deps"] # only needed for build-dependencies
如果您有[build-dependencies]
(例如 eg 。some_crate = "1.2.3"
),则需要将其添加到(主要)[dependencies]
(可悲的是{ {3}}),但您可以将它们设为可选:
[dependencies]
some_crate = { version = "1.2.3", optional = true }
[features]
build_deps = ["some_crate"]
$ cargo run --bin force-build --features build_deps
(如果没有$ cargo run --bin force-build
,则为[build-dependencies]
)
您甚至可以通过将build = "build.rs"
中的Cargo.toml
行替换为build = false
注意:由于OUT_DIR
目标没有bin
环境变量,因此如果您的build.rs
脚本使用env!("OUT_DIR")
,则可以通过以下方式“解决此问题”:改用concat!(env!("CARGO_MANIFEST_DIR"), "/target/")
。
答案 2 :(得分:2)
如果build.rs
发生变化,则Cargo已经重建了项目:
请注意,如果构建脚本本身(或其依赖项之一)发生更改,那么它将无条件地重建和重新运行,因此
cargo:rerun-if-changed=build.rs
几乎总是多余的(除非您想忽略除{之外的所有其他文件中的更改{1}})。 doc
在Linux上,我只会做build.rs
。对于Windows,请参见Windows equivalent of the Linux command 'touch'?
答案 3 :(得分:1)
如果您尝试基于非 Rust 或可能已更改的 include!()
文件进行重建,您可以使用
const _: &[u8] = include_bytes!("foobar.baz");
确保对这些文件的任何更改都会触发新的构建。非常确定此解决方案既不会增加时间也不会增加文件大小。
你也可以把它推到一个宏中,所以很容易做一堆文件。
macro_rules! build_on{($file:literal) => {
const _: &[u8] = include_bytes!($file);
}
build_on!("foobar.baz");
答案 4 :(得分:0)
如果在gitignore
下有目标(应该这样做),那么在开发和测试构建脚本时,这可能对文件的更改很有用。
if Path::new(".git/HEAD").exists() {
println!("cargo:rerun-if-changed=.git/HEAD");
}
答案 5 :(得分:0)
我可以提供最适合我的解决方案。
将以下内容添加到 build.rs 文件中,以使其每次都必须重新构建:
use failure::{format_err, Error};
use std::env;
use std::path::PathBuf;
use std::process::Command;
/// Just useful trait to run a command
trait RunIt {
fn run_it(&mut self, err: &str) -> Result<(), Error>;
}
impl RunIt for Command {
fn run_it(&mut self, err: &str) -> Result<(), Error> {
let output = self.output()?;
if !output.status.success() {
let out = String::from_utf8_lossy(&output.stderr);
eprintln!("{}", out);
Err(format_err!("{}", err))
} else {
Ok(())
}
}
}
fn main() -> Result<(), Error> {
// Your build stuff
// Activate this feature to rebuild this dependency everytime
if cfg!(feature = "refresh") {
Command::new("touch")
.args(&["build.rs"])
.run_it("Can't touch the build file")?;
}
Ok(())
}
将功能添加到 Cargo.toml 中以声明功能:
[package]
name = "sensitive-crate"
[features]
default = []
refresh = []
并激活刷新功能,以便每次都重建依赖关系:
[package]
name = "my_project_1"
[dependencies]
sensitive-crate = { path = "../sensitive-crate", features = ["refresh"] }