Skip to content

Commit d5630e1

Browse files
committed
Making build script API bit by bit
1 parent cdf0eb2 commit d5630e1

File tree

6 files changed

+135
-44
lines changed

6 files changed

+135
-44
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-build/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ license.workspace = true
1111
rustc_codegen_spirv-cache.workspace = true
1212
thiserror.workspace = true
1313
semver.workspace = true
14+
dunce.workspace = true
1415
log.workspace = true
1516

1617
[lints]
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
//! This module provides a `rust-gpu` shader crate builder
2+
//! usable inside of build scripts or as a part of CLI.
3+
4+
use std::{io, path::Path};
5+
6+
use crate::{
7+
lockfile::{LockfileMismatchError, LockfileMismatchHandler},
8+
spirv_builder::SpirvBuilder,
9+
spirv_cache::{
10+
command::CommandExecError,
11+
install::{Install, InstallError, InstallParams, InstalledBackend},
12+
toolchain::HaltToolchainInstallation,
13+
},
14+
};
15+
16+
/// Creates shader crate builder, allowing to modify install and build parameters separately.
17+
///
18+
/// # Errors
19+
///
20+
/// Returns an error if:
21+
///
22+
/// * the shader crate path is not valid,
23+
/// * the backend installation fails,
24+
/// * there is a lockfile version mismatch that cannot be resolved automatically.
25+
#[inline]
26+
#[expect(clippy::unreachable, reason = "target was already set")]
27+
pub fn shader_crate_builder<P, S, E, T, C, W>(
28+
shader_crate: P,
29+
target: S,
30+
mut build: SpirvBuilder,
31+
install: InstallParams,
32+
writer: W,
33+
halt_toolchain_installation: HaltToolchainInstallation<T, C>,
34+
) -> Result<ShaderCrateBuilder, MakeShaderBuilderError<E>>
35+
where
36+
P: AsRef<Path>,
37+
S: Into<String>,
38+
W: io::Write,
39+
E: From<CommandExecError>,
40+
T: FnOnce(&str) -> Result<(), E>,
41+
C: FnOnce(&str) -> Result<(), E>,
42+
{
43+
let shader_crate_path = dunce::canonicalize(shader_crate)?;
44+
let backend_args = Install::from_shader_crate_with_params(shader_crate_path, install);
45+
let backend = backend_args.run(writer, halt_toolchain_installation)?;
46+
47+
let lockfile_mismatch_handler = LockfileMismatchHandler::new(
48+
&backend_args.shader_crate,
49+
&backend.toolchain_channel,
50+
backend_args.params.force_overwrite_lockfiles_v4_to_v3,
51+
)?;
52+
53+
build.path_to_crate = Some(backend_args.shader_crate.clone());
54+
build.target = Some(target.into());
55+
backend
56+
.configure_spirv_builder(&mut build)
57+
.unwrap_or_else(|_| unreachable!("we set target before calling this function"));
58+
59+
Ok(ShaderCrateBuilder {
60+
builder: build,
61+
installed_backend_args: backend_args,
62+
installed_backend: backend,
63+
lockfile_mismatch_handler,
64+
})
65+
}
66+
67+
/// A builder for compiling a `rust-gpu` shader crate.
68+
#[derive(Debug, Clone)]
69+
#[non_exhaustive]
70+
pub struct ShaderCrateBuilder {
71+
/// The underlying builder for compiling the shader crate.
72+
pub builder: SpirvBuilder,
73+
/// The arguments used to install the backend.
74+
pub installed_backend_args: Install,
75+
/// The installed backend.
76+
pub installed_backend: InstalledBackend,
77+
/// The lockfile mismatch handler.
78+
pub lockfile_mismatch_handler: LockfileMismatchHandler,
79+
}
80+
81+
/// An error indicating what went wrong when creating a [`ShaderCrateBuilder`].
82+
#[derive(Debug, thiserror::Error)]
83+
#[non_exhaustive]
84+
pub enum MakeShaderBuilderError<E> {
85+
/// The given shader crate path is not valid.
86+
#[error("shader crate path is not valid: {0}")]
87+
InvalidCratePath(#[from] io::Error),
88+
/// The backend installation failed.
89+
#[error("could not install backend: {0}")]
90+
Install(#[from] InstallError<E>),
91+
/// There is a lockfile version mismatch that cannot be resolved automatically.
92+
#[error(transparent)]
93+
LockfileMismatch(#[from] LockfileMismatchError),
94+
}

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#![expect(clippy::pub_use, reason = "pub use for build scripts")]
2-
31
//! Rust GPU shader crate builder.
42
//!
53
//! This library allows you to easily compile your `rust-gpu` shaders,
@@ -8,14 +6,16 @@
86
//! # How it works
97
//!
108
//! This library manages installations of `rustc_codegen_spirv`
11-
//! using [`rustc_codegen_spirv-cache`](cache) crate.
9+
//! using [`rustc_codegen_spirv-cache`](spirv_cache) crate.
1210
//!
13-
//! Then is uses [`spirv-builder`](cache::spirv_builder) crate
11+
//! Then is uses [`spirv-builder`](spirv_builder) crate
1412
//! to pass the many additional parameters required to configure rustc and our codegen backend,
1513
//! but provide you with a toolchain-agnostic version that you may use from stable rustc.
1614
17-
pub use rustc_codegen_spirv_cache as cache;
15+
#![expect(clippy::pub_use, reason = "pub use for build scripts")]
1816

19-
pub mod lockfile;
17+
pub use rustc_codegen_spirv_cache as spirv_cache;
18+
pub use rustc_codegen_spirv_cache::spirv_builder;
2019

21-
// TODO build script API without shader crate path repetitions
20+
pub mod build;
21+
pub mod lockfile;

crates/cargo-gpu-build/src/lockfile.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ impl LockfileMismatchHandler {
228228
/// Returns an error if there was a problem reverting any of the lockfiles.
229229
/// See [`LockfileMismatchError`] for details.
230230
#[inline]
231-
pub fn revert_cargo_lock_manifest_versions(&self) -> Result<(), LockfileMismatchError> {
231+
pub fn revert_cargo_lock_manifest_versions(&mut self) -> Result<(), LockfileMismatchError> {
232232
for offending_cargo_lock in &self.cargo_lock_files_with_changed_manifest_versions {
233233
log::debug!("Reverting: {}", offending_cargo_lock.display());
234234
Self::replace_cargo_lock_manifest_version(offending_cargo_lock, "3", "4")?;
@@ -282,7 +282,7 @@ impl Drop for LockfileMismatchHandler {
282282
fn drop(&mut self) {
283283
let result = self.revert_cargo_lock_manifest_versions();
284284
if let Err(error) = result {
285-
log::error!("Couldn't revert some or all of the shader `Cargo.lock` files ({error})");
285+
log::error!("could not revert some or all of the shader `Cargo.lock` files ({error})");
286286
}
287287
}
288288
}
@@ -335,7 +335,7 @@ pub enum LockfileMismatchError {
335335
/// Conflicting lockfile manifest versions detected, with advice on how to resolve them
336336
/// by setting the [`force_overwrite_lockfiles_v4_to_v3`] flag.
337337
///
338-
/// [`force_overwrite_lockfiles_v4_to_v3`]: crate::cache::install::InstallParams::force_overwrite_lockfiles_v4_to_v3
338+
/// [`force_overwrite_lockfiles_v4_to_v3`]: crate::spirv_cache::install::InstallParams::force_overwrite_lockfiles_v4_to_v3
339339
#[error(
340340
r#"conflicting `Cargo.lock` versions detected ⚠️
341341

crates/cargo-gpu/src/build.rs

Lines changed: 29 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
//! `cargo gpu build`, analogous to `cargo build`
22
3-
#![allow(clippy::shadow_reuse, reason = "let's not be silly")]
4-
#![allow(clippy::unwrap_used, reason = "this is basically a test")]
5-
63
use core::convert::Infallible;
74
use std::{
85
io::{self, Write as _},
@@ -11,9 +8,11 @@ use std::{
118
};
129

1310
use anyhow::Context as _;
14-
use cargo_gpu_build::lockfile::LockfileMismatchHandler;
15-
use rustc_codegen_spirv_cache::install::Install;
16-
use spirv_builder::{CompileResult, ModuleResult, SpirvBuilder, Watch};
11+
use cargo_gpu_build::{
12+
build::shader_crate_builder,
13+
spirv_builder::{CompileResult, ModuleResult, SpirvBuilder, SpirvBuilderError, Watch},
14+
spirv_cache::install::Install,
15+
};
1716

1817
use crate::{linkage::Linkage, user_consent::ask_for_user_consent};
1918

@@ -73,19 +72,20 @@ impl Build {
7372
/// Returns an error if the build process fails somehow.
7473
#[inline]
7574
pub fn run(&mut self) -> anyhow::Result<()> {
76-
let skip_consent = self.install.params.auto_install_rust_toolchain;
77-
let halt_installation = ask_for_user_consent(skip_consent);
78-
let installed_backend = self.install.run(io::stdout(), halt_installation)?;
79-
80-
let _lockfile_mismatch_handler = LockfileMismatchHandler::new(
81-
&self.install.shader_crate,
82-
&installed_backend.toolchain_channel,
83-
self.install.params.force_overwrite_lockfiles_v4_to_v3,
75+
let crate_builder = shader_crate_builder(
76+
self.install.shader_crate.clone(),
77+
self.build
78+
.spirv_builder
79+
.target
80+
.as_deref()
81+
.ok_or(SpirvBuilderError::MissingTarget)?,
82+
self.build.spirv_builder.clone(),
83+
self.install.params.clone(),
84+
io::stdout(),
85+
ask_for_user_consent(self.install.params.auto_install_rust_toolchain),
8486
)?;
85-
86-
let builder = &mut self.build.spirv_builder;
87-
builder.path_to_crate = Some(self.install.shader_crate.clone());
88-
installed_backend.configure_spirv_builder(builder)?;
87+
self.install = crate_builder.installed_backend_args;
88+
self.build.spirv_builder = crate_builder.builder;
8989

9090
// Ensure the shader output dir exists
9191
log::debug!(
@@ -97,15 +97,6 @@ impl Build {
9797
log::debug!("canonicalized output dir: {}", canonicalized.display());
9898
self.build.output_dir = canonicalized;
9999

100-
// Ensure the shader crate exists
101-
self.install.shader_crate = dunce::canonicalize(&self.install.shader_crate)?;
102-
anyhow::ensure!(
103-
self.install.shader_crate.exists(),
104-
"shader crate '{}' does not exist. (Current dir is '{}')",
105-
self.install.shader_crate.display(),
106-
std::env::current_dir()?.display()
107-
);
108-
109100
if self.build.watch {
110101
let never = self.watch()?;
111102
match never {}
@@ -127,17 +118,21 @@ impl Build {
127118
/// Watches shader crate for changes using [`SpirvBuilder`].
128119
fn watch(&self) -> anyhow::Result<Infallible> {
129120
let this = self.clone();
121+
let watch = self
122+
.build
123+
.spirv_builder
124+
.watch(move |result, maybe_accept| {
125+
let parse_result = this.parse_compilation_result(&result);
126+
if let Some(accept) = maybe_accept {
127+
accept.submit(parse_result);
128+
}
129+
})?;
130+
130131
let Watch {
131132
first_compile,
132133
watch_thread,
133134
..
134-
} = self.build.spirv_builder.watch(move |result, accept| {
135-
let parse_result = this.parse_compilation_result(&result);
136-
if let Some(accept) = accept {
137-
accept.submit(parse_result);
138-
}
139-
})?;
140-
135+
} = watch;
141136
first_compile
142137
.context("should always return the first compile result")
143138
.flatten()?;

0 commit comments

Comments
 (0)