Skip to content

Commit ababc64

Browse files
committed
Decouple install codegen handling, add error types for it
1 parent 89d5713 commit ababc64

File tree

7 files changed

+88
-62
lines changed

7 files changed

+88
-62
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/cargo-gpu-cache/src/install.rs

Lines changed: 7 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -5,58 +5,14 @@ use std::path::{Path, PathBuf};
55
use anyhow::Context as _;
66
use rustc_codegen_spirv_cache::{
77
cache::cache_dir,
8+
install::InstalledBackend,
89
metadata::{query_metadata, MetadataExt as _},
910
spirv_source::{rust_gpu_toolchain_channel, SpirvSource},
1011
target_specs::update_target_specs_files,
12+
toolchain::ensure_toolchain_installation,
1113
};
12-
use spirv_builder::SpirvBuilder;
1314

14-
/// Represents a functional backend installation, whether it was cached or just installed.
15-
#[derive(Clone, Debug, Default)]
16-
#[non_exhaustive]
17-
pub struct InstalledBackend {
18-
/// path to the `rustc_codegen_spirv` dylib
19-
pub rustc_codegen_spirv_location: PathBuf,
20-
/// toolchain channel name
21-
pub toolchain_channel: String,
22-
/// directory with target-specs json files
23-
pub target_spec_dir: PathBuf,
24-
}
25-
26-
impl InstalledBackend {
27-
/// Creates a new `SpirvBuilder` configured to use this installed backend.
28-
#[expect(
29-
clippy::unreachable,
30-
reason = "it's unreachable, no need to return a Result"
31-
)]
32-
#[expect(clippy::impl_trait_in_params, reason = "forwarding spirv-builder API")]
33-
#[inline]
34-
pub fn to_spirv_builder(
35-
&self,
36-
path_to_crate: impl AsRef<Path>,
37-
target: impl Into<String>,
38-
) -> SpirvBuilder {
39-
let mut builder = SpirvBuilder::new(path_to_crate, target);
40-
self.configure_spirv_builder(&mut builder)
41-
.unwrap_or_else(|_| unreachable!("we set target before calling this function"));
42-
builder
43-
}
44-
45-
/// Configures the supplied [`SpirvBuilder`]. `SpirvBuilder.target` must be set and must not change after calling this function.
46-
///
47-
/// # Errors
48-
/// if `SpirvBuilder.target` is not set
49-
#[inline]
50-
pub fn configure_spirv_builder(&self, builder: &mut SpirvBuilder) -> anyhow::Result<()> {
51-
builder.rustc_codegen_spirv_location = Some(self.rustc_codegen_spirv_location.clone());
52-
builder.toolchain_overwrite = Some(self.toolchain_channel.clone());
53-
builder.path_to_target_spec = Some(self.target_spec_dir.join(format!(
54-
"{}.json",
55-
builder.target.as_ref().context("expect target to be set")?
56-
)));
57-
Ok(())
58-
}
59-
}
15+
use crate::user_consent::ask_for_user_consent;
6016

6117
/// Args for an install
6218
#[expect(
@@ -203,7 +159,8 @@ package = "rustc_codegen_spirv"
203159
Ok(())
204160
}
205161

206-
/// Install the binary pair and return the [`InstalledBackend`], from which you can create [`SpirvBuilder`] instances.
162+
/// Install the binary pair and return the [`InstalledBackend`],
163+
/// from which you can create [`SpirvBuilder`](spirv_builder::SpirvBuilder) instances.
207164
///
208165
/// # Errors
209166
/// If the installation somehow fails.
@@ -271,9 +228,9 @@ package = "rustc_codegen_spirv"
271228
.context("writing target spec files")?;
272229

273230
log::debug!("ensure_toolchain_and_components_exist");
274-
crate::install_toolchain::ensure_toolchain_and_components_exist(
231+
ensure_toolchain_installation(
275232
&toolchain_channel,
276-
self.auto_install_rust_toolchain,
233+
ask_for_user_consent(&toolchain_channel, self.auto_install_rust_toolchain),
277234
)
278235
.context("ensuring toolchain and components exist")?;
279236

crates/cargo-gpu-cache/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,11 @@ mod build;
4747
mod config;
4848
mod dump_usage;
4949
mod install;
50-
mod install_toolchain;
5150
mod linkage;
5251
mod lockfile;
5352
mod metadata;
5453
mod show;
54+
mod user_consent;
5555

5656
pub use install::*;
5757
pub use spirv_builder;

crates/cargo-gpu-cache/src/install_toolchain.rs renamed to crates/cargo-gpu-cache/src/user_consent.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
1-
//! toolchain installation logic
1+
//! User consent acquiring logic.
22
33
use anyhow::Context as _;
44
use crossterm::tty::IsTty as _;
55
use rustc_codegen_spirv_cache::toolchain::{
6-
ensure_toolchain_installation, HaltToolchainInstallation, REQUIRED_TOOLCHAIN_COMPONENTS,
6+
HaltToolchainInstallation, REQUIRED_TOOLCHAIN_COMPONENTS,
77
};
88

99
use crate::user_output;
1010

11-
/// Uses `rustup` to install the toolchain and all the [required components](REQUIRED_TOOLCHAIN_COMPONENTS),
12-
/// if not already installed, while additionally asking for the user consent.
13-
pub fn ensure_toolchain_and_components_exist(
11+
/// Halts the installation process of toolchain or its required components
12+
/// if the user does not consent to install either of them.
13+
pub fn ask_for_user_consent(
1414
channel: &str,
1515
skip_toolchain_install_consent: bool,
16-
) -> anyhow::Result<()> {
17-
let on_toolchain_install = || {
16+
) -> HaltToolchainInstallation<
17+
impl FnOnce() -> Result<(), anyhow::Error> + use<'_>,
18+
impl FnOnce() -> Result<(), anyhow::Error> + use<'_>,
19+
> {
20+
let on_toolchain_install = move || {
1821
let message = format!("Rust {channel} with `rustup`");
1922
get_consent_for_toolchain_install(
2023
format!("Install {message}").as_ref(),
@@ -24,7 +27,7 @@ pub fn ensure_toolchain_and_components_exist(
2427
user_output!("Installing {message}\n")?;
2528
Ok(())
2629
};
27-
let on_components_install = || {
30+
let on_components_install = move || {
2831
let message = format!(
2932
"components {REQUIRED_TOOLCHAIN_COMPONENTS:?} for toolchain {channel} with `rustup`"
3033
);
@@ -37,11 +40,10 @@ pub fn ensure_toolchain_and_components_exist(
3740
Ok(())
3841
};
3942

40-
let halt_installation = HaltToolchainInstallation {
43+
HaltToolchainInstallation {
4144
on_toolchain_install,
4245
on_components_install,
43-
};
44-
ensure_toolchain_installation(channel, halt_installation)
46+
}
4547
}
4648

4749
/// Prompt user if they want to install a new Rust toolchain.

crates/rustc_codegen_spirv-cache/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ keywords.workspace = true
88
license.workspace = true
99

1010
[dependencies]
11+
spirv-builder.workspace = true
1112
legacy_target_specs.workspace = true
1213
thiserror.workspace = true
1314
directories.workspace = true
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
//! Install a dedicated per-shader crate that has the `rust-gpu` compiler in it.
2+
3+
use std::path::{Path, PathBuf};
4+
5+
use spirv_builder::SpirvBuilder;
6+
7+
/// Represents a functional backend installation, whether it was cached or just installed.
8+
#[derive(Debug, Default, Clone)]
9+
// #[non_exhaustive] // TODO: uncomment
10+
#[expect(clippy::exhaustive_structs, reason = "this is temporary")] // TODO: remove
11+
pub struct InstalledBackend {
12+
/// Path to the `rustc_codegen_spirv` dylib.
13+
pub rustc_codegen_spirv_location: PathBuf,
14+
/// Toolchain channel name.
15+
pub toolchain_channel: String,
16+
/// Directory with target specs json files.
17+
pub target_spec_dir: PathBuf,
18+
}
19+
20+
impl InstalledBackend {
21+
/// Creates a new [`SpirvBuilder`] configured to use this installed backend.
22+
#[expect(
23+
clippy::unreachable,
24+
reason = "it's unreachable, no need to return a Result"
25+
)]
26+
#[expect(clippy::impl_trait_in_params, reason = "forwarding spirv-builder API")]
27+
#[inline]
28+
pub fn to_spirv_builder(
29+
&self,
30+
path_to_crate: impl AsRef<Path>,
31+
target: impl Into<String>,
32+
) -> SpirvBuilder {
33+
let mut builder = SpirvBuilder::new(path_to_crate, target);
34+
self.configure_spirv_builder(&mut builder)
35+
.unwrap_or_else(|_| unreachable!("we set target before calling this function"));
36+
builder
37+
}
38+
39+
/// Configures the supplied [`SpirvBuilder`].
40+
/// [`SpirvBuilder::target`] must be set and must not change after calling this function.
41+
///
42+
/// # Errors
43+
///
44+
/// Returns an error if [`SpirvBuilder::target`] is not set.
45+
#[inline]
46+
pub fn configure_spirv_builder(
47+
&self,
48+
builder: &mut SpirvBuilder,
49+
) -> Result<(), TargetNotSetError> {
50+
builder.rustc_codegen_spirv_location = Some(self.rustc_codegen_spirv_location.clone());
51+
builder.toolchain_overwrite = Some(self.toolchain_channel.clone());
52+
53+
let target = builder.target.as_deref().ok_or(TargetNotSetError)?;
54+
builder.path_to_target_spec = Some(self.target_spec_dir.join(format!("{target}.json")));
55+
Ok(())
56+
}
57+
}
58+
59+
/// An error indicating that [`SpirvBuilder::target`] was not set.
60+
#[derive(Debug, Clone, thiserror::Error)]
61+
#[non_exhaustive]
62+
#[error("target should be set")]
63+
pub struct TargetNotSetError;

crates/rustc_codegen_spirv-cache/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@
1919
#![expect(clippy::pub_use, reason = "reexport for convenience")]
2020

2121
pub use cargo_metadata;
22+
pub use spirv_builder;
2223

2324
pub mod cache;
25+
pub mod install;
2426
pub mod metadata;
2527
pub mod spirv_source;
2628
pub mod target_specs;

0 commit comments

Comments
 (0)