Skip to content

Commit 43b02b0

Browse files
committed
create target-specs folder per installation, pulled from rustc_codegen_spirv_target_specs, with legacy fallback
1 parent 0d774ef commit 43b02b0

File tree

9 files changed

+123
-37
lines changed

9 files changed

+123
-37
lines changed

Cargo.lock

Lines changed: 8 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ exclude = [
1313
resolver = "2"
1414

1515
[workspace.dependencies]
16-
spirv-builder = { git = "https://github.com/Rust-GPU/rust-gpu.git", rev = "6d7c1cd6c0920500a3fa8c01c23e7b74302c15c4", default-features = false }
16+
spirv-builder = { git = "https://github.com/Rust-GPU/rust-gpu.git", rev = "9b99f208414473ff39afacbf91b0c29f3bd6b3e3", default-features = false }
1717
anyhow = "1.0.94"
1818
clap = { version = "4.5.37", features = ["derive"] }
1919
crossterm = "0.28.1"
@@ -29,6 +29,9 @@ test-log = "0.2.16"
2929
cargo_metadata = "0.19.2"
3030
semver = "1.0.26"
3131

32+
# This crate MUST NEVER be upgraded, we need this particular "first" version to support old rust-gpu builds
33+
legacy_target_specs = { git = "https://github.com/Rust-GPU/rust-gpu.git", rev = "9b99f208414473ff39afacbf91b0c29f3bd6b3e3", package = "rustc_codegen_spirv-target-specs", features = ["include_str"] }
34+
3235
[workspace.lints.rust]
3336
missing_docs = "warn"
3437

crates/cargo-gpu/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ default-run = "cargo-gpu"
1414
cargo_metadata.workspace = true
1515
anyhow.workspace = true
1616
spirv-builder = { workspace = true, features = ["clap", "watch"] }
17+
legacy_target_specs.workspace = true
1718
clap.workspace = true
1819
directories.workspace = true
1920
env_logger.workspace = true

crates/cargo-gpu/src/install.rs

Lines changed: 75 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
//! Install a dedicated per-shader crate that has the `rust-gpu` compiler in it.
22
3+
use crate::legacy_target_specs::write_legacy_target_specs;
34
use crate::spirv_source::{
45
get_channel_from_rustc_codegen_spirv_build_script, query_metadata, FindPackage as _,
56
};
6-
use crate::{cache_dir, spirv_source::SpirvSource, target_spec_dir};
7+
use crate::{cache_dir, spirv_source::SpirvSource};
78
use anyhow::Context as _;
8-
use log::trace;
9-
use spirv_builder::{SpirvBuilder, TARGET_SPECS};
10-
use std::io::Write as _;
9+
use cargo_metadata::Metadata;
10+
use log::{info, trace};
11+
use spirv_builder::SpirvBuilder;
1112
use std::path::{Path, PathBuf};
1213

1314
/// Args for an install
@@ -83,14 +84,16 @@ pub struct InstalledBackend {
8384
pub rustc_codegen_spirv_location: PathBuf,
8485
/// toolchain channel name
8586
pub toolchain_channel: String,
87+
/// directory with target-specs json files
88+
pub target_spec_dir: PathBuf,
8689
}
8790

8891
impl InstalledBackend {
8992
/// Configures the supplied [`SpirvBuilder`]. `SpirvBuilder.target` must be set and must not change after calling this function.
9093
pub fn configure_spirv_builder(&self, builder: &mut SpirvBuilder) -> anyhow::Result<()> {
9194
builder.rustc_codegen_spirv_location = Some(self.rustc_codegen_spirv_location.clone());
9295
builder.toolchain_overwrite = Some(self.toolchain_channel.clone());
93-
builder.path_to_target_spec = Some(target_spec_dir()?.join(format!(
96+
builder.path_to_target_spec = Some(self.target_spec_dir.join(format!(
9497
"{}.json",
9598
builder.target.as_ref().context("expect target to be set")?
9699
)));
@@ -169,22 +172,72 @@ package = "rustc_codegen_spirv"
169172
Ok(())
170173
}
171174

172-
/// Add the target spec files to the crate.
173-
fn write_target_spec_files(&self) -> anyhow::Result<()> {
174-
for (filename, contents) in TARGET_SPECS {
175-
let path = target_spec_dir()
176-
.context("creating target spec dir")?
177-
.join(filename);
178-
if !path.is_file() || self.rebuild_codegen {
179-
let mut file = std::fs::File::create(&path)
180-
.with_context(|| format!("creating file at [{}]", path.display()))?;
181-
file.write_all(contents.as_bytes())
182-
.context("writing to file")?;
175+
/// Copy spec files from one dir to another, assuming no subdirectories
176+
fn copy_spec_files(src: &Path, dst: &Path) -> anyhow::Result<()> {
177+
info!(
178+
"Copy target specs from {:?} to {:?}",
179+
src.display(),
180+
dst.display()
181+
);
182+
std::fs::create_dir_all(dst)?;
183+
let dir = std::fs::read_dir(src)?;
184+
for dir_entry in dir {
185+
let file = dir_entry?;
186+
let file_path = file.path();
187+
if file_path.is_file() {
188+
std::fs::copy(file_path, dst.join(file.file_name()))?;
183189
}
184190
}
185191
Ok(())
186192
}
187193

194+
/// Add the target spec files to the crate.
195+
fn update_spec_files(
196+
&self,
197+
source: &SpirvSource,
198+
install_dir: &Path,
199+
dummy_metadata: &Metadata,
200+
skip_rebuild: bool,
201+
) -> anyhow::Result<PathBuf> {
202+
let mut target_specs_dst = install_dir.join("target-specs");
203+
if !skip_rebuild {
204+
if let Ok(target_specs) =
205+
dummy_metadata.find_package("rustc_codegen_spirv-target-specs")
206+
{
207+
let target_specs_src = target_specs
208+
.manifest_path
209+
.as_std_path()
210+
.parent()
211+
.and_then(|p| {
212+
let src = p.join("target-specs");
213+
src.is_dir().then_some(src)
214+
})
215+
.context("Could not find `target-specs` directory within `rustc_codegen_spirv-target-specs` dependency")?;
216+
if source.is_path() {
217+
// skip copy
218+
target_specs_dst = target_specs_src;
219+
} else {
220+
// copy over the target-specs
221+
Self::copy_spec_files(&target_specs_src, &target_specs_dst)
222+
.context("copying target-specs json files")?;
223+
}
224+
} else {
225+
// use legacy target specs bundled with cargo gpu
226+
if source.is_path() {
227+
// This is a stupid situation:
228+
// * We can't be certain that there are `target-specs` in the local checkout (there may be some in `spirv-builder`)
229+
// * We can't dump our legacy ones into the `install_dir`, as that would modify the local rust-gpu checkout
230+
// -> do what the old cargo gpu did, one global dir for all target specs
231+
// and hope parallel runs don't shred each other
232+
target_specs_dst = cache_dir()?.join("legacy-target-specs-for-local-checkout");
233+
}
234+
write_legacy_target_specs(&target_specs_dst, self.rebuild_codegen)?;
235+
}
236+
}
237+
238+
Ok(target_specs_dst)
239+
}
240+
188241
/// Install the binary pair and return the `(dylib_path, toolchain_channel)`.
189242
#[expect(clippy::too_many_lines, reason = "it's fine")]
190243
pub fn run(&self) -> anyhow::Result<InstalledBackend> {
@@ -245,6 +298,11 @@ package = "rustc_codegen_spirv"
245298
)?;
246299
log::info!("selected toolchain channel `{toolchain_channel:?}`");
247300

301+
log::debug!("update_spec_files");
302+
let target_spec_dir = self
303+
.update_spec_files(&source, &install_dir, &dummy_metadata, skip_rebuild)
304+
.context("writing target spec files")?;
305+
248306
if !skip_rebuild {
249307
log::debug!("ensure_toolchain_and_components_exist");
250308
crate::install_toolchain::ensure_toolchain_and_components_exist(
@@ -304,15 +362,12 @@ package = "rustc_codegen_spirv"
304362
log::error!("could not find {}", dylib_path.display());
305363
anyhow::bail!("`rustc_codegen_spirv` build failed");
306364
}
307-
308-
log::debug!("write_target_spec_files");
309-
self.write_target_spec_files()
310-
.context("writing target spec files")?;
311365
}
312366

313367
Ok(InstalledBackend {
314368
rustc_codegen_spirv_location: dest_dylib_path,
315369
toolchain_channel,
370+
target_spec_dir,
316371
})
317372
}
318373
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//! Legacy target specs are spec jsons for versions before `rustc_codegen_spirv-target-specs`
2+
//! came bundled with them. Instead, cargo gpu needs to bundle these legacy spec files. Luckily,
3+
//! they are the same for all versions, as bundling target specs with the codegen backend was
4+
//! introduced before the first target spec update.
5+
6+
use anyhow::Context as _;
7+
use log::info;
8+
use std::path::Path;
9+
10+
/// Extract legacy target specs from our executable into some directory
11+
pub fn write_legacy_target_specs(target_spec_dir: &Path, rebuild: bool) -> anyhow::Result<()> {
12+
info!(
13+
"Writing legacy target specs to {}",
14+
target_spec_dir.display()
15+
);
16+
std::fs::create_dir_all(target_spec_dir)?;
17+
for (filename, contents) in legacy_target_specs::TARGET_SPECS {
18+
let path = target_spec_dir.join(filename);
19+
if !path.is_file() || rebuild {
20+
std::fs::write(&path, contents.as_bytes()).with_context(|| {
21+
format!("writing legacy target spec file at [{}]", path.display())
22+
})?;
23+
}
24+
}
25+
Ok(())
26+
}

crates/cargo-gpu/src/main.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ mod build;
5959
mod config;
6060
mod install;
6161
mod install_toolchain;
62+
mod legacy_target_specs;
6263
mod linkage;
6364
mod lockfile;
6465
mod metadata;
@@ -201,13 +202,6 @@ fn cache_dir() -> anyhow::Result<std::path::PathBuf> {
201202
})
202203
}
203204

204-
/// Location of the target spec metadata files
205-
fn target_spec_dir() -> anyhow::Result<std::path::PathBuf> {
206-
let dir = cache_dir()?.join("target-specs");
207-
std::fs::create_dir_all(&dir)?;
208-
Ok(dir)
209-
}
210-
211205
/// Convenience function for internal use. Dumps all the CLI usage instructions. Useful for
212206
/// updating the README.
213207
fn dump_full_usage_for_readme() -> anyhow::Result<()> {

crates/cargo-gpu/src/spirv_source.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ mod test {
253253
source,
254254
SpirvSource::Git {
255255
url: "https://github.com/Rust-GPU/rust-gpu".to_owned(),
256-
rev: "82a0f69008414f51d59184763146caa6850ac588".to_owned()
256+
rev: "86edfffac1d2fe349211576617ffc22a176de2a3".to_owned()
257257
}
258258
);
259259
}
@@ -275,6 +275,6 @@ mod test {
275275
.to_str()
276276
.map(std::string::ToString::to_string)
277277
.unwrap();
278-
assert_eq!("https___github_com_Rust-GPU_rust-gpu+82a0f690", &name);
278+
assert_eq!("https___github_com_Rust-GPU_rust-gpu+86edfffa", &name);
279279
}
280280
}

crates/shader-crate-template/Cargo.lock

Lines changed: 5 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/shader-crate-template/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ crate-type = ["rlib", "cdylib"]
99
# Dependencies for CPU and GPU code
1010
[dependencies]
1111
# TODO: use a simple crate version once v0.10.0 is released
12-
spirv-std = { git = "https://github.com/Rust-GPU/rust-gpu", rev = "82a0f69" }
12+
spirv-std = { git = "https://github.com/Rust-GPU/rust-gpu", rev = "86edfffac1d2fe349211576617ffc22a176de2a3" }
1313

1414
# Dependencies for GPU code
1515
[target.'cfg(target_arch = "spirv")'.dependencies]

0 commit comments

Comments
 (0)