Running `cargo run` on build.rs of another workspace crate

Hello,

I have this situation where my project is separated in crates using a workspace.

[workspace]
members = [
    "main_app",           // binary app
    "resource_packer"     // binary app
]

My goal is to use resource_packer as a helper application to package assets to my main binary program main_app. The resource_packer loads files from disk, processes them and saves them back to disk.

main_app has a build.rs where I am trying to build a script that would check if the assets that resource_packer is supposed to process have changed, and if they have, the build.rs script should re-run the resource_packer binary and collect its generated files to the disposal of main_app.

On main_app's build.rs I am trying to use this command:

Command::new("cargo run --bin resource_packer").spawn().expect("Failed to run asset packer").wait();

but I get an error error: failed to run custom build command for.... Why is that? How can I run a binary crate of a workspace inside another binary crate's build.rs script?

Running cargo from a build script seems incredibly sketchy, but I can point you to one problem: The Rust command struct does not do any splitting on spaces. You have to split each argument yourself. Currently, you are trying to run an executable containing spaces and dashes in its name.

Thanks for the tip. Unfortunately the build process hangs even when the Command is constructed properly.

The user invoked cargo and the build script invoked cargo probably both try to lock the same lockfile for the workspace. The build script invoked cargo will thus hang until the user invoked cargo exots, which waits for the build script to finish, thus resulting in a deadlock. You can try not using a shared workspace for the crates.

1 Like

Another option would be to build resource_packer before and call the binary /target/release/resource_packer (please check if this is the right path) directly. This way you don't have to invoke cargo twice

I think this solution is good enough for the time being, thanks!

For anyone else reading, keep in mind that with this only the location of the binary changes and thus if the binary tries to relatively access the resource files there won't be any in the target/ directory. You can copy the assets next to the built binary or change the current directory manually to the original location. This seemed to work for me:

    let cmd = env!("CARGO_MANIFEST_DIR");
    let project_root = Path::new(cmd);
    std::env::set_current_dir(project_root).expect("Cannot set cd");