Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 24 additions & 15 deletions crates/spirv-builder/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -883,6 +883,29 @@ fn join_checking_for_separators(strings: Vec<impl Borrow<str>>, sep: &str) -> St
strings.join(sep)
}

impl SpirvBuilder {
/// The absolute target dir: [`Self::target_dir_path`] (default `spirv-builder`), relative to
/// the shader crate's cargo target dir unless already absolute.
///
/// Relative paths need `cargo metadata`, which is slow, so the watcher resolves this only once.
fn resolve_target_dir(&self, path_to_crate: &Path) -> Result<PathBuf, cargo_metadata::Error> {
let target_dir_path = self
.target_dir_path
.clone()
.unwrap_or_else(|| PathBuf::from("spirv-builder"));
if target_dir_path.is_absolute() {
return Ok(target_dir_path);
}
let metadata = cargo_metadata::MetadataCommand::new()
.current_dir(path_to_crate)
.exec()?;
Ok(metadata
.target_directory
.into_std_path_buf()
.join(target_dir_path))
}
}

pub struct RustcOutput {
pub compile_result: CompileResult,
pub deps: Vec<RawString>,
Expand Down Expand Up @@ -1048,21 +1071,7 @@ impl SpirvBuilder {
rustflags.extend(extra_rustflags.split_whitespace().map(|s| s.to_string()));
}

let target_dir_path = self
.target_dir_path
.clone()
.unwrap_or_else(|| PathBuf::from("spirv-builder"));
let target_dir = if target_dir_path.is_absolute() {
target_dir_path
} else {
let metadata = cargo_metadata::MetadataCommand::new()
.current_dir(path_to_crate)
.exec()?;
metadata
.target_directory
.into_std_path_buf()
.join(target_dir_path)
};
let target_dir = self.resolve_target_dir(path_to_crate)?;

let mut cargo = cargo_cmd::CargoCmd::new();
if let Some(toolchain) = &self.toolchain_overwrite {
Expand Down
30 changes: 30 additions & 0 deletions crates/spirv-builder/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,33 @@ mod dylib_lookup {
);
}
}

mod target_dir {
use crate::SpirvBuilder;
use std::path::{Path, PathBuf};

fn sky_shader() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR")).join("../../examples/shaders/sky-shader")
}

#[test]
fn absolute_target_dir_is_kept() {
let abs = std::env::temp_dir().join("my-spirv-target");
let mut builder = SpirvBuilder::new(sky_shader(), "spirv-unknown-vulkan1.2");
builder.target_dir_path = Some(abs.clone());
// a crate path without a `Cargo.toml`: `cargo metadata` would fail if it ran
let not_a_crate = std::env::temp_dir();
assert_eq!(builder.resolve_target_dir(&not_a_crate).unwrap(), abs);
}

#[test]
fn relative_target_dir_is_inside_cargo_target_dir() {
let builder = SpirvBuilder::new(sky_shader(), "spirv-unknown-vulkan1.2");
let resolved = builder.resolve_target_dir(&sky_shader()).unwrap();
assert!(resolved.is_absolute(), "{resolved:?}");
assert!(
resolved.ends_with("spirv-builder") && resolved != Path::new("spirv-builder"),
"{resolved:?}"
);
}
}
15 changes: 15 additions & 0 deletions crates/spirv-builder/src/watch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ impl SpirvWatcher {
Err(TryRecvError::Disconnected) => return Err(SpirvWatcherError::WatcherDied.into()),
}

self.pin_target_dir();
let result = (|| {
let out = self.builder.invoke_rustc()?;
self.watch_leaf_deps(out.deps.iter().map(|d| d.as_ref()));
Expand Down Expand Up @@ -151,6 +152,20 @@ impl SpirvWatcher {
}
}

/// Resolves a relative target dir to an absolute one once, so rebuilds don't each have to
/// run `cargo metadata`. Failures are left for [`SpirvBuilder::invoke_rustc`] to report, and
/// resolving is retried on the next build.
fn pin_target_dir(&mut self) {
let is_absolute = (self.builder.target_dir_path.as_ref()).is_some_and(|p| p.is_absolute());
if is_absolute || !self.path_to_crate.is_dir() {
return;
}
match self.builder.resolve_target_dir(&self.path_to_crate) {
Ok(target_dir) => self.builder.target_dir_path = Some(target_dir),
Err(err) => log::debug!("couldn't resolve target dir yet: {err}"),
}
}

fn watch_leaf_deps<'a>(&mut self, deps: impl Iterator<Item = &'a RawStr>) {
for dep in deps {
let path = dep.to_path().unwrap();
Expand Down