2
votes

I have a Rust crate which is a wrapper for a large C API and takes several minutes to compile. Running cargo build in the directory without making any changes always results in a recompile. It seems that Cargo should not be recompiling this crate unless I make a change, which I have not done.

I would like to compile the crate once and avoid re-compiling the crate unless I make a change. Is there any way for me to avoid constantly recompiling this scrate?

It seems that something is likely incorrect in my crate's build script. I will try to create a minimal reproducible example, but in the meantime I have provided the build script below:

use std::env;
use std::fs::copy;
use std::path::Path;
use std::process::Command;

fn main() {
    let out_dir = env::var("OUT_DIR").unwrap();
    let c_src_path = Path::new("parasail_c");

    // configure the build
    Command::new("cmake")
        .arg(".")
        .current_dir(&c_src_path)
        .output()
        .expect("Failed to configure parasail.");

    // build the library
    Command::new("make")
        .current_dir(&c_src_path)
        .output()
        .expect("Failed to build parasail.");

    // put the static library in the right directory so we can clean up
    let target_file = format!("{}/libparasail.so", out_dir);
    copy("parasail_c/libparasail.so", target_file)
        .expect("Problem copying library to target directoy.");

    let target_file = format!("{}/parasail.h", out_dir);
    copy("parasail_c/parasail.h", target_file)
        .expect("Problem copying header to target directoy.");

    // clean up the temporary build files
    Command::new("make")
        .current_dir(&c_src_path)
        .arg("clean")
        .output()
        .expect("Failed to clean up build files.");

    // clean up the configuration files
    Command::new("make")
        .arg("distclean")
        .current_dir(&c_src_path)
        .output()
        .expect("Failed to clean up configuration files.");

    // let cargo know that it can find the file in the out directory
    println!("cargo:rustc-link-search=native={}", out_dir);
    println!("cargo:rustc-link-lib=dylib=parasail");
}

Here is the output from cargo build --verbose

cargo build --verbose
   Compiling parasail-sys v0.1.0 (/home/fortier/testcode/rust/pairhmm/parasail-sys)
       Fresh libc v0.2.51
     Running `/home/fortier/testcode/rust/pairhmm/parasail-sys/target/debug/build/parasail-sys-f2d2d1f27a70b4d4/build-script-build`
     Running `rustc --edition=2018 --crate-name parasail_sys src/lib.rs --color always --crate-type lib --emit=dep-info,link -C debuginfo=2 -C metadata=8879665b3d9bf7e1 -C extra-filename=-8879665b3d9bf7e1 --out-dir /home/fortier/testcode/rust/pairhmm/parasail-sys/target/debug/deps -C incremental=/home/fortier/testcode/rust/pairhmm/parasail-sys/target/debug/incremental -L dependency=/home/fortier/testcode/rust/pairhmm/parasail-sys/target/debug/deps --extern libc=/home/fortier/testcode/rust/pairhmm/parasail-sys/target/debug/deps/liblibc-bc949bf21f4fe772.rlib -L native=/home/fortier/testcode/rust/pairhmm/parasail-sys/target/debug/build/parasail-sys-2ac393455c1f3545/out -l dylib=parasail`
    Finished dev [unoptimized + debuginfo] target(s) in 1m 58s

After further inspection I have discovered that the issue is somewhere in the C code that the sub-crate is wrapping. I replaced the current C code with an older version, while changing none of the Rust code and the issue has disappeared. I'll continue doing some further investigation to see exactly what was causing the problem and I'll update this post once I narrow it down.

1
FWIW, you don't need Path::new here due to generics. You can just say let c_src_path = "parasail_c"; and .current_dir(c_src_path). - Shepmaster
FWIW, since you are ignoring the data from output, it's probably lighter to use status - Shepmaster
Please include the Cargo.toml for the parasail-sys crate. - Shepmaster
It sounds like your build script / CMake / the Makefile is modifying the C files as it compiles them. That would cause a rebuild each time. Perhaps touch all the files in the crate with a known timestamp, run the build, then use a tool like find to show files that are not the same as that known timestamp. - Shepmaster

1 Answers

0
votes

Add to the build script println!("cargo:rerun-if-changed={}", &file); lines for each file and for each directory.