Как я могу принудительно запустить build.rs без очистки всего моего проекта? Я проверил cargo build --help, но не смог найти ничего, связанного с build.rs.

13
tversteeg 2 Мар 2018 в 23:47

4 ответа

Если build.rs изменяется, Cargo уже перестраивает проект:

Обратите внимание, что если сам скрипт сборки (или одна из его зависимостей) изменяется, то он перестраивается и перезапускается безоговорочно, поэтому cargo:rerun-if-changed=build.rs почти всегда избыточен (если вы не хотите игнорировать изменения во всех других файлах, кроме {{X1} } ) . doc

В Linux я просто сделаю touch build.rs && cargo build. Для Windows см. Windows-эквивалент команды Linux «touch»?

6
Shepmaster 6 Апр 2019 в 19:17

Зарегистрируйте build.rs как цель bin ящика:

  1. Добавьте это в ваш Cargo.toml файл:

    [package]
    edition = "2018"
    build = "build.rs"
    
    [[bin]]
    name = "force-build"
    path = "build.rs"
    required-features = ["build_deps"]  # only needed for build-dependencies
    
  2. Если у вас есть [build-dependencies] ( например . some_crate = "1.2.3"), вам нужно добавить их в (основной) [dependencies] (к сожалению, нет [bin-dependencies] на данный момент), но вы можете сделать их необязательными:

    [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 env var отсутствует для bin целей, если ваш build.rs сценарий использует env!("OUT_DIR"), вы можете "исправить это" с помощью concat!(env!("CARGO_MANIFEST_DIR"), "/target/") вместо.

4
Daniel H-M 5 Апр 2019 в 12:41

Я могу предложить решение, которое работает для меня хорошо.

Добавьте следующее в файл 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 = []

И активируйте функцию refresh , чтобы каждый раз перестраивать зависимость:

[package]
name = "my_project_1"

[dependencies]
sensitive-crate = { path = "../sensitive-crate", features = ["refresh"] }
1
DenisKolodin 7 Июл 2019 в 01:29

Если у вас есть цель в gitignore (что и нужно), это может быть полезно для любых изменений файлов при разработке и тестировании сценария сборки.

if Path::new(".git/HEAD").exists() {
    println!("cargo:rerun-if-changed=.git/HEAD");
}
1
Seivan 4 Май 2019 в 16:34